summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-04-15 19:22:02 +1000
committerAndreas Kling <kling@serenityos.org>2021-04-17 10:21:23 +0200
commitecfa7cb824eaddd375dd10334f53da2f1f371b65 (patch)
treef371f2f7fec38b02d6f12407f5a62492eef242f4 /Kernel
parent42b1eb5af1177800f383960be0932447e4a7cb5e (diff)
downloadserenity-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.txt3
-rw-r--r--Kernel/VirtIO/VirtIO.cpp9
-rw-r--r--Kernel/VirtIO/VirtIO.h1
-rw-r--r--Kernel/VirtIO/VirtIOConsole.cpp20
-rw-r--r--Kernel/VirtIO/VirtIOConsole.h4
-rw-r--r--Kernel/VirtIO/VirtIOQueue.cpp6
-rw-r--r--Kernel/VirtIO/VirtIOQueue.h5
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();