mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +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
Notes:
sideshowbarker
2024-07-18 19:31:31 +09:00
Author: https://github.com/IdanHo Commit: https://github.com/SerenityOS/serenity/commit/ecfa7cb824e Pull-request: https://github.com/SerenityOS/serenity/pull/6340
8 changed files with 35 additions and 18 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
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) {
|
||||
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;
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -53,7 +53,10 @@ $SERENITY_EXTRA_QEMU_ARGS
|
|||
-drive file=${SERENITY_DISK_IMAGE},format=raw,index=0,media=disk
|
||||
-device ich9-ahci
|
||||
-usb
|
||||
-debugcon stdio
|
||||
-device virtio-serial
|
||||
-chardev stdio,id=stdout,mux=on
|
||||
-device virtconsole,chardev=stdout
|
||||
-device isa-debugcon,chardev=stdout
|
||||
-soundhw pcspk
|
||||
-device sb16
|
||||
"
|
||||
|
|
Loading…
Add table
Reference in a new issue