Kernel: Make VirtIO::Queue construction fallible

This commit is contained in:
Idan Horowitz 2022-01-21 11:51:02 +02:00 committed by Andreas Kling
parent 17584d8a84
commit c3099382b8
Notes: sideshowbarker 2024-07-17 23:02:37 +09:00
3 changed files with 26 additions and 15 deletions

View file

@ -327,9 +327,10 @@ bool Device::setup_queue(u16 queue_index)
u16 queue_notify_offset = config_read16(*m_common_cfg, COMMON_CFG_QUEUE_NOTIFY_OFF);
auto queue = make<Queue>(queue_size, queue_notify_offset);
if (queue->is_null())
auto queue_or_error = Queue::try_create(queue_size, queue_notify_offset);
if (queue_or_error.is_error())
return false;
auto queue = queue_or_error.release_value();
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());

View file

@ -9,19 +9,28 @@
namespace Kernel::VirtIO {
Queue::Queue(u16 queue_size, u16 notify_offset)
: m_queue_size(queue_size)
, m_notify_offset(notify_offset)
, m_free_buffers(queue_size)
ErrorOr<NonnullOwnPtr<Queue>> Queue::try_create(u16 queue_size, u16 notify_offset)
{
size_t size_of_descriptors = sizeof(QueueDescriptor) * queue_size;
size_t size_of_driver = sizeof(QueueDriver) + queue_size * sizeof(u16);
size_t size_of_device = sizeof(QueueDevice) + queue_size * sizeof(QueueDeviceItem);
auto queue_region_size = Memory::page_round_up(size_of_descriptors + size_of_driver + size_of_device).release_value_but_fixme_should_propagate_errors();
auto queue_region_size = TRY(Memory::page_round_up(size_of_descriptors + size_of_driver + size_of_device));
OwnPtr<Memory::Region> queue_region;
if (queue_region_size <= PAGE_SIZE)
m_queue_region = MM.allocate_kernel_region(queue_region_size, "VirtIO Queue", Memory::Region::Access::ReadWrite).release_value();
queue_region = TRY(MM.allocate_kernel_region(queue_region_size, "VirtIO Queue"sv, Memory::Region::Access::ReadWrite));
else
m_queue_region = MM.allocate_contiguous_kernel_region(queue_region_size, "VirtIO Queue", Memory::Region::Access::ReadWrite).release_value();
queue_region = TRY(MM.allocate_contiguous_kernel_region(queue_region_size, "VirtIO Queue"sv, Memory::Region::Access::ReadWrite));
return adopt_nonnull_own_or_enomem(new (nothrow) Queue(queue_region.release_nonnull(), queue_size, notify_offset));
}
Queue::Queue(NonnullOwnPtr<Memory::Region> queue_region, u16 queue_size, u16 notify_offset)
: m_queue_size(queue_size)
, m_notify_offset(notify_offset)
, m_free_buffers(queue_size)
, m_queue_region(move(queue_region))
{
size_t size_of_descriptors = sizeof(QueueDescriptor) * queue_size;
size_t size_of_driver = sizeof(QueueDriver) + queue_size * sizeof(u16);
// TODO: ensure alignment!!!
u8* ptr = m_queue_region->vaddr().as_ptr();
memset(ptr, 0, m_queue_region->size());
@ -29,9 +38,8 @@ Queue::Queue(u16 queue_size, u16 notify_offset)
m_driver = reinterpret_cast<QueueDriver*>(ptr + size_of_descriptors);
m_device = reinterpret_cast<QueueDevice*>(ptr + size_of_descriptors + size_of_driver);
for (auto i = 0; i + 1 < queue_size; i++) {
m_descriptors[i].next = i + 1; // link all of the descriptors in a line
}
for (auto i = 0; i + 1 < queue_size; i++)
m_descriptors[i].next = i + 1; // link all the descriptors in a line
enable_interrupts();
}

View file

@ -28,10 +28,10 @@ enum class BufferType {
class Queue {
public:
Queue(u16 queue_size, u16 notify_offset);
static ErrorOr<NonnullOwnPtr<Queue>> try_create(u16 queue_size, u16 notify_offset);
~Queue();
bool is_null() const { return !m_queue_region; }
u16 notify_offset() const { return m_notify_offset; }
void enable_interrupts();
@ -52,6 +52,8 @@ public:
bool should_notify() const;
private:
Queue(NonnullOwnPtr<Memory::Region> queue_region, u16 queue_size, u16 notify_offset);
void reclaim_buffer_chain(u16 chain_start_index, u16 chain_end_index, size_t length_of_chain);
PhysicalAddress to_physical(const void* ptr) const
@ -93,7 +95,7 @@ private:
QueueDescriptor* m_descriptors { nullptr };
QueueDriver* m_driver { nullptr };
QueueDevice* m_device { nullptr };
OwnPtr<Memory::Region> m_queue_region;
NonnullOwnPtr<Memory::Region> m_queue_region;
Spinlock m_lock;
friend class QueueChain;