mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:27:45 +00:00
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>
This commit is contained in:
parent
42b1eb5af1
commit
ecfa7cb824
8 changed files with 35 additions and 18 deletions
|
@ -220,6 +220,9 @@ set(KERNEL_SOURCES
|
||||||
TimerQueue.cpp
|
TimerQueue.cpp
|
||||||
UBSanitizer.cpp
|
UBSanitizer.cpp
|
||||||
UserOrKernelBuffer.cpp
|
UserOrKernelBuffer.cpp
|
||||||
|
VirtIO/VirtIO.cpp
|
||||||
|
VirtIO/VirtIOConsole.cpp
|
||||||
|
VirtIO/VirtIOQueue.cpp
|
||||||
VM/AnonymousVMObject.cpp
|
VM/AnonymousVMObject.cpp
|
||||||
VM/ContiguousVMObject.cpp
|
VM/ContiguousVMObject.cpp
|
||||||
VM/InodeVMObject.cpp
|
VM/InodeVMObject.cpp
|
||||||
|
|
|
@ -217,6 +217,10 @@ bool VirtIODevice::accept_device_features(u64 device_features, u64 accepted_feat
|
||||||
accepted_features &= ~(VIRTIO_F_RING_PACKED);
|
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, "{}: Device features: {}", m_class_name, device_features);
|
||||||
dbgln_if(VIRTIO_DEBUG, "{}: Accepted features: {}", m_class_name, accepted_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)
|
void VirtIODevice::supply_buffer_and_notify(u16 queue_index, const u8* buffer, u32 len, BufferType buffer_type)
|
||||||
{
|
{
|
||||||
VERIFY(queue_index < m_queue_count);
|
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);
|
notify_queue(queue_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +360,6 @@ u8 VirtIODevice::isr_status()
|
||||||
void VirtIODevice::handle_irq(const RegisterState&)
|
void VirtIODevice::handle_irq(const RegisterState&)
|
||||||
{
|
{
|
||||||
u8 isr_type = isr_status();
|
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 (isr_type & DEVICE_CONFIG_INTERRUPT) {
|
||||||
if (!handle_device_config_change()) {
|
if (!handle_device_config_change()) {
|
||||||
set_status_bit(DEVICE_STATUS_FAILED);
|
set_status_bit(DEVICE_STATUS_FAILED);
|
||||||
|
@ -369,6 +372,8 @@ void VirtIODevice::handle_irq(const RegisterState&)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isr_type & ~(QUEUE_INTERRUPT | DEVICE_CONFIG_INTERRUPT))
|
||||||
|
dbgln("{}: Handling interrupt with unknown type: {}", m_class_name, isr_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace Kernel {
|
||||||
|
|
||||||
#define VIRTIO_F_VERSION_1 ((u64)1 << 32)
|
#define VIRTIO_F_VERSION_1 ((u64)1 << 32)
|
||||||
#define VIRTIO_F_RING_PACKED ((u64)1 << 34)
|
#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_COMMON_CFG 1
|
||||||
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
|
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
|
||||||
|
|
|
@ -61,9 +61,14 @@ VirtIOConsole::VirtIOConsole(PCI::Address address)
|
||||||
get_queue(RECEIVEQ).on_data_available = [&]() {
|
get_queue(RECEIVEQ).on_data_available = [&]() {
|
||||||
dbgln("VirtIOConsole: receive_queue 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 = [&]() {
|
get_queue(TRANSMITQ).on_data_available = [&]() {
|
||||||
dbgln("VirtIOConsole: send_queue 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");
|
dbgln("TODO: Populate receive queue with a receive buffer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,17 +106,14 @@ KResultOr<size_t> VirtIOConsole::write(FileDescription&, u64, const UserOrKernel
|
||||||
{
|
{
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
|
VERIFY(size <= PAGE_SIZE);
|
||||||
|
|
||||||
dbgln("VirtIOConsole: Write with size {}, kernel: {}", size, data.is_kernel_buffer());
|
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);
|
||||||
|
|
||||||
ssize_t nread = data.read_buffered<256>(size, [&](const u8* bytes, size_t bytes_count) {
|
return size;
|
||||||
supply_buffer_and_notify(TRANSMITQ, bytes, bytes_count, BufferType::DeviceReadable);
|
|
||||||
return (ssize_t)bytes_count;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (nread < 0)
|
|
||||||
return Kernel::KResult((ErrnoCode)-nread);
|
|
||||||
return (size_t)nread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,8 @@ private:
|
||||||
virtual bool handle_device_config_change() override;
|
virtual bool handle_device_config_change() override;
|
||||||
virtual String device_name() const override { return String::formatted("hvc{}", minor()); }
|
virtual String device_name() const override { return String::formatted("hvc{}", minor()); }
|
||||||
|
|
||||||
VirtIOQueue* m_receive_queue { nullptr };
|
OwnPtr<Region> m_receive_region;
|
||||||
VirtIOQueue* m_send_queue { nullptr };
|
OwnPtr<Region> m_transmit_region;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,15 +64,15 @@ void VirtIOQueue::disable_interrupts()
|
||||||
m_driver->flags = 1;
|
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);
|
VERIFY(m_free_buffers > 0);
|
||||||
|
|
||||||
auto descriptor_index = m_free_head;
|
auto descriptor_index = m_free_head;
|
||||||
m_descriptors[descriptor_index].flags = static_cast<u16>(buffer_type);
|
m_descriptors[descriptor_index].flags = static_cast<u16>(buffer_type);
|
||||||
m_descriptors[descriptor_index].address = reinterpret_cast<u64>(buffer);
|
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_buffers--;
|
||||||
m_free_head = (m_free_head + 1) % m_queue_size;
|
m_free_head = (m_free_head + 1) % m_queue_size;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Badge.h>
|
||||||
#include <Kernel/SpinLock.h>
|
#include <Kernel/SpinLock.h>
|
||||||
#include <Kernel/VM/MemoryManager.h>
|
#include <Kernel/VM/MemoryManager.h>
|
||||||
|
|
||||||
|
@ -36,6 +37,8 @@ enum class BufferType {
|
||||||
DeviceWritable = 2
|
DeviceWritable = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VirtIODevice;
|
||||||
|
|
||||||
class VirtIOQueue {
|
class VirtIOQueue {
|
||||||
public:
|
public:
|
||||||
VirtIOQueue(u16 queue_size, u16 notify_offset);
|
VirtIOQueue(u16 queue_size, u16 notify_offset);
|
||||||
|
@ -51,7 +54,7 @@ public:
|
||||||
PhysicalAddress driver_area() const { return to_physical(m_driver.ptr()); }
|
PhysicalAddress driver_area() const { return to_physical(m_driver.ptr()); }
|
||||||
PhysicalAddress device_area() const { return to_physical(m_device.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 new_data_available() const;
|
||||||
|
|
||||||
bool handle_interrupt();
|
bool handle_interrupt();
|
||||||
|
|
|
@ -53,7 +53,10 @@ $SERENITY_EXTRA_QEMU_ARGS
|
||||||
-drive file=${SERENITY_DISK_IMAGE},format=raw,index=0,media=disk
|
-drive file=${SERENITY_DISK_IMAGE},format=raw,index=0,media=disk
|
||||||
-device ich9-ahci
|
-device ich9-ahci
|
||||||
-usb
|
-usb
|
||||||
-debugcon stdio
|
-device virtio-serial
|
||||||
|
-chardev stdio,id=stdout,mux=on
|
||||||
|
-device virtconsole,chardev=stdout
|
||||||
|
-device isa-debugcon,chardev=stdout
|
||||||
-soundhw pcspk
|
-soundhw pcspk
|
||||||
-device sb16
|
-device sb16
|
||||||
"
|
"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue