1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:17:34 +00:00

Kernel: Modernize use of pointers in VirtIO

Raw pointers were mostly replaced with smart pointers and references
where appropriate based on kling and smartcomputer7's suggestions :)

Co-authored-by: Sahan <sahan.h.fernando@gmail.com>
This commit is contained in:
Idan Horowitz 2021-04-15 19:12:06 +10:00 committed by Andreas Kling
parent ea4c9efbb9
commit 4a467c553a
6 changed files with 146 additions and 156 deletions

View file

@ -44,9 +44,9 @@ void VirtIO::detect()
});
}
VirtIODevice::VirtIODevice(PCI::Address address, const char* class_name)
VirtIODevice::VirtIODevice(PCI::Address address, String class_name)
: PCI::Device(address, PCI::get_interrupt_line(address))
, m_class_name(class_name)
, m_class_name(move(class_name))
, m_io_base(IOAddress(PCI::get_BAR0(pci_address()) & ~1))
{
dbgln("{}: Found @ {}", m_class_name, pci_address());
@ -60,45 +60,40 @@ VirtIODevice::VirtIODevice(PCI::Address address, const char* class_name)
for (auto& capability : capabilities) {
if (capability.id() == PCI_CAPABILITY_VENDOR_SPECIFIC) {
// We have a virtio_pci_cap
Configuration cfg = {};
cfg.cfg_type = capability.read8(0x3);
switch (cfg.cfg_type) {
case VIRTIO_PCI_CAP_COMMON_CFG:
case VIRTIO_PCI_CAP_NOTIFY_CFG:
case VIRTIO_PCI_CAP_ISR_CFG:
case VIRTIO_PCI_CAP_DEVICE_CFG:
case VIRTIO_PCI_CAP_PCI_CFG: {
auto cap_length = capability.read8(0x2);
if (cap_length < 0x10) {
dbgln("{}: Unexpected capability size: {}", m_class_name, cap_length);
break;
}
cfg.bar = capability.read8(0x4);
if (cfg.bar > 0x5) {
dbgln("{}: Unexpected capability bar value: {}", m_class_name, cfg.bar);
break;
}
cfg.offset = capability.read32(0x8);
cfg.length = capability.read32(0xc);
dbgln_if(VIRTIO_DEBUG, "{}: Found configuration {}, bar: {}, offset: {}, length: {}", m_class_name, cfg.cfg_type, cfg.bar, cfg.offset, cfg.length);
m_configs.append(cfg);
auto cfg = make<Configuration>();
auto raw_config_type = capability.read8(0x3);
if (raw_config_type < static_cast<u8>(ConfigurationType::Common) || raw_config_type > static_cast<u8>(ConfigurationType::PCI)) {
dbgln("{}: Unknown capability configuration type: {}", m_class_name, raw_config_type);
return;
}
cfg->cfg_type = static_cast<ConfigurationType>(raw_config_type);
auto cap_length = capability.read8(0x2);
if (cap_length < 0x10) {
dbgln("{}: Unexpected capability size: {}", m_class_name, cap_length);
break;
}
cfg->bar = capability.read8(0x4);
if (cfg->bar > 0x5) {
dbgln("{}: Unexpected capability bar value: {}", m_class_name, cfg->bar);
break;
}
cfg->offset = capability.read32(0x8);
cfg->length = capability.read32(0xc);
dbgln_if(VIRTIO_DEBUG, "{}: Found configuration {}, bar: {}, offset: {}, length: {}", m_class_name, (u32)cfg->cfg_type, cfg->bar, cfg->offset, cfg->length);
if (cfg->cfg_type == ConfigurationType::Common)
m_use_mmio = true;
else if (cfg->cfg_type == ConfigurationType::Notify)
m_notify_multiplier = capability.read32(0x10);
if (cfg.cfg_type == VIRTIO_PCI_CAP_COMMON_CFG)
m_use_mmio = true;
else if (cfg.cfg_type == VIRTIO_PCI_CAP_NOTIFY_CFG)
m_notify_multiplier = capability.read32(0x10);
break;
}
default:
dbgln("{}: Unknown capability configuration type: {}", m_class_name, cfg.cfg_type);
break;
}
m_configs.append(move(cfg));
}
}
m_common_cfg = get_config(VIRTIO_PCI_CAP_COMMON_CFG, 0);
m_notify_cfg = get_config(VIRTIO_PCI_CAP_NOTIFY_CFG, 0);
m_isr_cfg = get_config(VIRTIO_PCI_CAP_ISR_CFG, 0);
if (m_use_mmio) {
m_common_cfg = get_config(ConfigurationType::Common, 0);
m_notify_cfg = get_config(ConfigurationType::Notify, 0);
m_isr_cfg = get_config(ConfigurationType::ISR, 0);
}
set_status_bit(DEVICE_STATUS_DRIVER);
}
@ -123,80 +118,80 @@ auto VirtIODevice::mapping_for_bar(u8 bar) -> MappedMMIO&
void VirtIODevice::notify_queue(u16 queue_index)
{
dbgln("VirtIODevice: notifying about queue change at idx: {}", queue_index);
if (!m_use_mmio)
if (!m_notify_cfg)
out<u16>(REG_QUEUE_NOTIFY, queue_index);
else
config_write16(m_notify_cfg, get_queue(queue_index)->notify_offset() * m_notify_multiplier, queue_index);
config_write16(*m_notify_cfg, get_queue(queue_index).notify_offset() * m_notify_multiplier, queue_index);
}
u8 VirtIODevice::config_read8(const Configuration* config, u32 offset)
u8 VirtIODevice::config_read8(const Configuration& config, u32 offset)
{
return mapping_for_bar(config->bar).read<u8>(config->offset + offset);
return mapping_for_bar(config.bar).read<u8>(config.offset + offset);
}
u16 VirtIODevice::config_read16(const Configuration* config, u32 offset)
u16 VirtIODevice::config_read16(const Configuration& config, u32 offset)
{
return mapping_for_bar(config->bar).read<u16>(config->offset + offset);
return mapping_for_bar(config.bar).read<u16>(config.offset + offset);
}
u32 VirtIODevice::config_read32(const Configuration* config, u32 offset)
u32 VirtIODevice::config_read32(const Configuration& config, u32 offset)
{
return mapping_for_bar(config->bar).read<u32>(config->offset + offset);
return mapping_for_bar(config.bar).read<u32>(config.offset + offset);
}
void VirtIODevice::config_write8(const Configuration* config, u32 offset, u8 value)
void VirtIODevice::config_write8(const Configuration& config, u32 offset, u8 value)
{
mapping_for_bar(config->bar).write(config->offset + offset, value);
mapping_for_bar(config.bar).write(config.offset + offset, value);
}
void VirtIODevice::config_write16(const Configuration* config, u32 offset, u16 value)
void VirtIODevice::config_write16(const Configuration& config, u32 offset, u16 value)
{
mapping_for_bar(config->bar).write(config->offset + offset, value);
mapping_for_bar(config.bar).write(config.offset + offset, value);
}
void VirtIODevice::config_write32(const Configuration* config, u32 offset, u32 value)
void VirtIODevice::config_write32(const Configuration& config, u32 offset, u32 value)
{
mapping_for_bar(config->bar).write(config->offset + offset, value);
mapping_for_bar(config.bar).write(config.offset + offset, value);
}
void VirtIODevice::config_write64(const Configuration* config, u32 offset, u64 value)
void VirtIODevice::config_write64(const Configuration& config, u32 offset, u64 value)
{
mapping_for_bar(config->bar).write(config->offset + offset, value);
mapping_for_bar(config.bar).write(config.offset + offset, value);
}
u8 VirtIODevice::read_status_bits()
{
if (!m_use_mmio)
if (!m_common_cfg)
return in<u8>(REG_DEVICE_STATUS);
return config_read8(m_common_cfg, COMMON_CFG_DEVICE_STATUS);
return config_read8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS);
}
void VirtIODevice::clear_status_bit(u8 status_bit)
{
m_status &= status_bit;
if (!m_use_mmio)
if (!m_common_cfg)
out<u8>(REG_DEVICE_STATUS, m_status);
else
config_write8(m_common_cfg, COMMON_CFG_DEVICE_STATUS, m_status);
config_write8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS, m_status);
}
void VirtIODevice::set_status_bit(u8 status_bit)
{
m_status |= status_bit;
if (!m_use_mmio)
if (!m_common_cfg)
out<u8>(REG_DEVICE_STATUS, m_status);
else
config_write8(m_common_cfg, COMMON_CFG_DEVICE_STATUS, m_status);
config_write8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS, m_status);
}
u64 VirtIODevice::get_device_features()
{
if (!m_use_mmio)
if (!m_common_cfg)
return in<u32>(REG_DEVICE_FEATURES);
config_write32(m_common_cfg, COMMON_CFG_DEVICE_FEATURE_SELECT, 0);
auto lower_bits = config_read32(m_common_cfg, COMMON_CFG_DEVICE_FEATURE);
config_write32(m_common_cfg, COMMON_CFG_DEVICE_FEATURE_SELECT, 1);
u64 upper_bits = (u64)config_read32(m_common_cfg, COMMON_CFG_DEVICE_FEATURE) << 32;
config_write32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE_SELECT, 0);
auto lower_bits = config_read32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE);
config_write32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE_SELECT, 1);
u64 upper_bits = (u64)config_read32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE) << 32;
return upper_bits | lower_bits;
}
@ -208,24 +203,24 @@ bool VirtIODevice::accept_device_features(u64 device_features, u64 accepted_feat
if (is_feature_set(device_features, VIRTIO_F_VERSION_1)) {
accepted_features |= VIRTIO_F_VERSION_1;
} else {
dbgln("{}: legacy device detected", m_class_name);
dbgln_if(VIRTIO_DEBUG, "{}: legacy device detected", m_class_name);
}
if (is_feature_set(device_features, VIRTIO_F_RING_PACKED)) {
dbgln("{}: packed queues not yet supported", m_class_name);
dbgln_if(VIRTIO_DEBUG, "{}: packed queues not yet supported", m_class_name);
accepted_features &= ~(VIRTIO_F_RING_PACKED);
}
dbgln("VirtIOConsole: Device features: {}", device_features);
dbgln("VirtIOConsole: Accepted features: {}", accepted_features);
dbgln_if(VIRTIO_DEBUG, "{}: Device features: {}", m_class_name, device_features);
dbgln_if(VIRTIO_DEBUG, "{}: Accepted features: {}", m_class_name, accepted_features);
if (!m_use_mmio) {
if (!m_common_cfg) {
out<u32>(REG_GUEST_FEATURES, accepted_features);
} else {
config_write32(m_common_cfg, COMMON_CFG_DRIVER_FEATURE_SELECT, 0);
config_write32(m_common_cfg, COMMON_CFG_DRIVER_FEATURE, accepted_features);
config_write32(m_common_cfg, COMMON_CFG_DRIVER_FEATURE_SELECT, 1);
config_write32(m_common_cfg, COMMON_CFG_DRIVER_FEATURE, accepted_features >> 32);
config_write32(*m_common_cfg, COMMON_CFG_DRIVER_FEATURE_SELECT, 0);
config_write32(*m_common_cfg, COMMON_CFG_DRIVER_FEATURE, accepted_features);
config_write32(*m_common_cfg, COMMON_CFG_DRIVER_FEATURE_SELECT, 1);
config_write32(*m_common_cfg, COMMON_CFG_DRIVER_FEATURE, accepted_features >> 32);
}
set_status_bit(DEVICE_STATUS_FEATURES_OK);
m_status = read_status_bits();
@ -240,58 +235,44 @@ bool VirtIODevice::accept_device_features(u64 device_features, u64 accepted_feat
return true;
}
auto VirtIODevice::get_common_config(u32 index) const -> const Configuration*
{
if (index == 0)
return m_common_cfg;
return get_config(VIRTIO_PCI_CAP_COMMON_CFG, index);
}
auto VirtIODevice::get_device_config(u32 index) const -> const Configuration*
{
return get_config(VIRTIO_PCI_CAP_DEVICE_CFG, index);
}
void VirtIODevice::reset_device()
{
dbgln_if(VIRTIO_DEBUG, "{}: Reset device", m_class_name);
if (!m_use_mmio) {
if (!m_common_cfg) {
clear_status_bit(0);
while (read_status_bits() != 0) {
// TODO: delay a bit?
}
return;
} else if (m_common_cfg) {
config_write8(m_common_cfg, COMMON_CFG_DEVICE_STATUS, 0);
while (config_read8(m_common_cfg, COMMON_CFG_DEVICE_STATUS) != 0) {
// TODO: delay a bit?
}
return;
}
dbgln_if(VIRTIO_DEBUG, "{}: No handle to device, cant reset", m_class_name);
config_write8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS, 0);
while (config_read8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS) != 0) {
// TODO: delay a bit?
}
return;
}
bool VirtIODevice::setup_queue(u16 queue_index)
{
if (!m_use_mmio || !m_common_cfg)
if (!m_common_cfg)
return false;
config_write16(m_common_cfg, COMMON_CFG_QUEUE_SELECT, queue_index);
u16 queue_size = config_read16(m_common_cfg, COMMON_CFG_QUEUE_SIZE);
config_write16(*m_common_cfg, COMMON_CFG_QUEUE_SELECT, queue_index);
u16 queue_size = config_read16(*m_common_cfg, COMMON_CFG_QUEUE_SIZE);
if (queue_size == 0) {
dbgln_if(VIRTIO_DEBUG, "{}: Queue[{}] is unavailable!", m_class_name, queue_index);
return true;
}
u16 queue_notify_offset = config_read16(m_common_cfg, COMMON_CFG_QUEUE_NOTIFY_OFF);
u16 queue_notify_offset = config_read16(*m_common_cfg, COMMON_CFG_QUEUE_NOTIFY_OFF);
auto queue = make<VirtIOQueue>(queue_size, queue_notify_offset);
if (queue->is_null())
return false;
config_write64(m_common_cfg, COMMON_CFG_QUEUE_DESC, queue->descriptor_area().get());
config_write64(m_common_cfg, COMMON_CFG_QUEUE_DRIVER, queue->driver_area().get());
config_write64(m_common_cfg, COMMON_CFG_QUEUE_DEVICE, queue->device_area().get());
config_write64(*m_common_cfg, COMMON_CFG_QUEUE_DESC, queue->descriptor_area().get());
config_write64(*m_common_cfg, COMMON_CFG_QUEUE_DRIVER, queue->driver_area().get());
config_write64(*m_common_cfg, COMMON_CFG_QUEUE_DEVICE, queue->device_area().get());
dbgln_if(VIRTIO_DEBUG, "{}: Queue[{}] size: {}", m_class_name, queue_index, queue_size);
@ -307,7 +288,7 @@ void VirtIODevice::set_requested_queue_count(u16 count)
bool VirtIODevice::setup_queues()
{
if (m_common_cfg) {
auto maximum_queue_count = config_read16(m_common_cfg, COMMON_CFG_NUM_QUEUES);
auto maximum_queue_count = config_read16(*m_common_cfg, COMMON_CFG_NUM_QUEUES);
if (m_queue_count == 0) {
m_queue_count = maximum_queue_count;
} else if (m_queue_count > maximum_queue_count) {
@ -340,23 +321,27 @@ bool VirtIODevice::finish_init()
void VirtIODevice::supply_buffer_and_notify(u16 queue_index, const u8* buffer, u32 len, BufferType buffer_type)
{
VERIFY(queue_index < m_queue_count);
if (get_queue(queue_index)->supply_buffer(buffer, len, buffer_type))
if (get_queue(queue_index).supply_buffer(buffer, len, buffer_type))
notify_queue(queue_index);
}
u8 VirtIODevice::isr_status()
{
if (!m_use_mmio)
if (!m_isr_cfg)
return in<u8>(REG_ISR_STATUS);
return config_read8(m_isr_cfg, 0);
return config_read8(*m_isr_cfg, 0);
}
void VirtIODevice::handle_irq(const RegisterState&)
{
u8 isr_type = isr_status();
dbgln_if(VIRTIO_DEBUG, "VirtIODevice: Handling interrupt with status: {}", isr_type);
if (isr_type & DEVICE_CONFIG_INTERRUPT)
handle_device_config_change();
if (isr_type & DEVICE_CONFIG_INTERRUPT) {
if (!handle_device_config_change()) {
set_status_bit(DEVICE_STATUS_FAILED);
dbgln("{}: Failed to handle device config change!", m_class_name);
}
}
if (isr_type & QUEUE_INTERRUPT) {
for (auto& queue : m_queues) {
if (queue.handle_interrupt())