diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2021-04-15 19:22:02 +1000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-17 10:21:23 +0200 |
commit | ecfa7cb824eaddd375dd10334f53da2f1f371b65 (patch) | |
tree | f371f2f7fec38b02d6f12407f5a62492eef242f4 /Kernel | |
parent | 42b1eb5af1177800f383960be0932447e4a7cb5e (diff) | |
download | serenity-ecfa7cb824eaddd375dd10334f53da2f1f371b65.zip |
Kernel: Implement a naive version of virtconsole by memcpying to physical page
This patch allocates a physical page for each of the virtqueues and
memcpys to it when receiving a buffer to get a physical, aligned
contiguous buffer as required by the virtio specification.
Co-authored-by: Sahan <sahan.h.fernando@gmail.com>
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Kernel/VirtIO/VirtIO.cpp | 9 | ||||
-rw-r--r-- | Kernel/VirtIO/VirtIO.h | 1 | ||||
-rw-r--r-- | Kernel/VirtIO/VirtIOConsole.cpp | 20 | ||||
-rw-r--r-- | Kernel/VirtIO/VirtIOConsole.h | 4 | ||||
-rw-r--r-- | Kernel/VirtIO/VirtIOQueue.cpp | 6 | ||||
-rw-r--r-- | Kernel/VirtIO/VirtIOQueue.h | 5 |
7 files changed, 31 insertions, 17 deletions
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 3c083ea4e6..052badfc59 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -220,6 +220,9 @@ set(KERNEL_SOURCES TimerQueue.cpp UBSanitizer.cpp UserOrKernelBuffer.cpp + VirtIO/VirtIO.cpp + VirtIO/VirtIOConsole.cpp + VirtIO/VirtIOQueue.cpp VM/AnonymousVMObject.cpp VM/ContiguousVMObject.cpp VM/InodeVMObject.cpp diff --git a/Kernel/VirtIO/VirtIO.cpp b/Kernel/VirtIO/VirtIO.cpp index ee2f01833f..e04654a6d5 100644 --- a/Kernel/VirtIO/VirtIO.cpp +++ b/Kernel/VirtIO/VirtIO.cpp @@ -217,6 +217,10 @@ bool VirtIODevice::accept_device_features(u64 device_features, u64 accepted_feat accepted_features &= ~(VIRTIO_F_RING_PACKED); } + if (is_feature_set(device_features, VIRTIO_F_IN_ORDER)) { + accepted_features |= VIRTIO_F_IN_ORDER; + } + dbgln_if(VIRTIO_DEBUG, "{}: Device features: {}", m_class_name, device_features); dbgln_if(VIRTIO_DEBUG, "{}: Accepted features: {}", m_class_name, accepted_features); @@ -342,7 +346,7 @@ 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); } @@ -356,7 +360,6 @@ u8 VirtIODevice::isr_status() void VirtIODevice::handle_irq(const RegisterState&) { u8 isr_type = isr_status(); - dbgln_if(VIRTIO_DEBUG, "{}: Handling interrupt with status: {}", m_class_name, isr_type); if (isr_type & DEVICE_CONFIG_INTERRUPT) { if (!handle_device_config_change()) { set_status_bit(DEVICE_STATUS_FAILED); @@ -369,6 +372,8 @@ void VirtIODevice::handle_irq(const RegisterState&) return; } } + if (isr_type & ~(QUEUE_INTERRUPT | DEVICE_CONFIG_INTERRUPT)) + dbgln("{}: Handling interrupt with unknown type: {}", m_class_name, isr_type); } } diff --git a/Kernel/VirtIO/VirtIO.h b/Kernel/VirtIO/VirtIO.h index e5c98db1f1..5723b7338a 100644 --- a/Kernel/VirtIO/VirtIO.h +++ b/Kernel/VirtIO/VirtIO.h @@ -56,6 +56,7 @@ namespace Kernel { #define VIRTIO_F_VERSION_1 ((u64)1 << 32) #define VIRTIO_F_RING_PACKED ((u64)1 << 34) +#define VIRTIO_F_IN_ORDER ((u64)1 << 35) #define VIRTIO_PCI_CAP_COMMON_CFG 1 #define VIRTIO_PCI_CAP_NOTIFY_CFG 2 diff --git a/Kernel/VirtIO/VirtIOConsole.cpp b/Kernel/VirtIO/VirtIOConsole.cpp index 27b27b3d9e..1838a977c7 100644 --- a/Kernel/VirtIO/VirtIOConsole.cpp +++ b/Kernel/VirtIO/VirtIOConsole.cpp @@ -61,9 +61,14 @@ VirtIOConsole::VirtIOConsole(PCI::Address address) get_queue(RECEIVEQ).on_data_available = [&]() { dbgln("VirtIOConsole: receive_queue on_data_available"); }; + m_receive_region = MM.allocate_contiguous_kernel_region(PAGE_SIZE, "VirtIOConsole Receive", Region::Access::Read | Region::Access::Write); + if (m_receive_region) { + supply_buffer_and_notify(RECEIVEQ, m_receive_region->physical_page(0)->paddr().as_ptr(), m_receive_region->size(), BufferType::DeviceWritable); + } get_queue(TRANSMITQ).on_data_available = [&]() { dbgln("VirtIOConsole: send_queue on_data_available"); }; + m_transmit_region = MM.allocate_contiguous_kernel_region(PAGE_SIZE, "VirtIOConsole Transmit", Region::Access::Read | Region::Access::Write); dbgln("TODO: Populate receive queue with a receive buffer"); } } @@ -101,17 +106,14 @@ KResultOr<size_t> VirtIOConsole::write(FileDescription&, u64, const UserOrKernel { if (!size) return 0; + VERIFY(size <= PAGE_SIZE); - dbgln("VirtIOConsole: Write with size {}, kernel: {}", size, data.is_kernel_buffer()); - - ssize_t nread = data.read_buffered<256>(size, [&](const u8* bytes, size_t bytes_count) { - supply_buffer_and_notify(TRANSMITQ, bytes, bytes_count, BufferType::DeviceReadable); - return (ssize_t)bytes_count; - }); + if (!data.read(m_transmit_region->vaddr().as_ptr(), size)) { + return Kernel::KResult((ErrnoCode)-EFAULT); + } + supply_buffer_and_notify(TRANSMITQ, m_transmit_region->physical_page(0)->paddr().as_ptr(), size, BufferType::DeviceReadable); - if (nread < 0) - return Kernel::KResult((ErrnoCode)-nread); - return (size_t)nread; + return size; } } diff --git a/Kernel/VirtIO/VirtIOConsole.h b/Kernel/VirtIO/VirtIOConsole.h index da997a0c40..9d9aff4427 100644 --- a/Kernel/VirtIO/VirtIOConsole.h +++ b/Kernel/VirtIO/VirtIOConsole.h @@ -59,8 +59,8 @@ private: virtual bool handle_device_config_change() override; virtual String device_name() const override { return String::formatted("hvc{}", minor()); } - VirtIOQueue* m_receive_queue { nullptr }; - VirtIOQueue* m_send_queue { nullptr }; + OwnPtr<Region> m_receive_region; + OwnPtr<Region> m_transmit_region; }; } diff --git a/Kernel/VirtIO/VirtIOQueue.cpp b/Kernel/VirtIO/VirtIOQueue.cpp index 1afbbca066..fa485948c1 100644 --- a/Kernel/VirtIO/VirtIOQueue.cpp +++ b/Kernel/VirtIO/VirtIOQueue.cpp @@ -64,15 +64,15 @@ void VirtIOQueue::disable_interrupts() m_driver->flags = 1; } -bool VirtIOQueue::supply_buffer(const u8* buffer, u32 len, BufferType buffer_type) +bool VirtIOQueue::supply_buffer(Badge<VirtIODevice>, const u8* buffer, u32 length, BufferType buffer_type) { - VERIFY(buffer && len > 0); + VERIFY(buffer && length > 0); VERIFY(m_free_buffers > 0); auto descriptor_index = m_free_head; m_descriptors[descriptor_index].flags = static_cast<u16>(buffer_type); m_descriptors[descriptor_index].address = reinterpret_cast<u64>(buffer); - m_descriptors[descriptor_index].length = len; + m_descriptors[descriptor_index].length = length; m_free_buffers--; m_free_head = (m_free_head + 1) % m_queue_size; diff --git a/Kernel/VirtIO/VirtIOQueue.h b/Kernel/VirtIO/VirtIOQueue.h index 003d0a807f..1959925507 100644 --- a/Kernel/VirtIO/VirtIOQueue.h +++ b/Kernel/VirtIO/VirtIOQueue.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/Badge.h> #include <Kernel/SpinLock.h> #include <Kernel/VM/MemoryManager.h> @@ -36,6 +37,8 @@ enum class BufferType { DeviceWritable = 2 }; +class VirtIODevice; + class VirtIOQueue { public: VirtIOQueue(u16 queue_size, u16 notify_offset); @@ -51,7 +54,7 @@ public: PhysicalAddress driver_area() const { return to_physical(m_driver.ptr()); } PhysicalAddress device_area() const { return to_physical(m_device.ptr()); } - bool supply_buffer(const u8* buffer, u32 len, BufferType); + bool supply_buffer(Badge<VirtIODevice>, const u8* buffer, u32 length, BufferType); bool new_data_available() const; bool handle_interrupt(); |