mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-01 20:10:28 +00:00
Kernel: Add support for reading from VirtIOConsole
This allows two-way communication with the host through a VirtIOConsole. This is necessary for features like clipboard sharing.
This commit is contained in:
parent
1c06d77262
commit
1492bb2fd6
Notes:
sideshowbarker
2024-07-18 10:02:01 +09:00
Author: https://github.com/X-yl Commit: https://github.com/SerenityOS/serenity/commit/1492bb2fd68 Pull-request: https://github.com/SerenityOS/serenity/pull/8257 Reviewed-by: https://github.com/IdanHo Reviewed-by: https://github.com/alimpfard Reviewed-by: https://github.com/ccapitalK
5 changed files with 74 additions and 8 deletions
|
@ -53,9 +53,6 @@ set(KERNEL_SOURCES
|
|||
Devices/RandomDevice.cpp
|
||||
Devices/SB16.cpp
|
||||
Devices/SerialDevice.cpp
|
||||
VirtIO/VirtIO.cpp
|
||||
VirtIO/VirtIOQueue.cpp
|
||||
VirtIO/VirtIOConsole.cpp
|
||||
Devices/VMWareBackdoor.cpp
|
||||
Devices/ZeroDevice.cpp
|
||||
Devices/HID/I8042Controller.cpp
|
||||
|
|
|
@ -30,6 +30,25 @@ bool RingBuffer::copy_data_in(const UserOrKernelBuffer& buffer, size_t offset, s
|
|||
return false;
|
||||
}
|
||||
|
||||
KResultOr<size_t> RingBuffer::copy_data_out(size_t size, UserOrKernelBuffer& buffer) const
|
||||
{
|
||||
auto start = m_start_of_used % m_capacity_in_bytes;
|
||||
auto num_bytes = min(min(m_num_used_bytes, size), m_capacity_in_bytes - start);
|
||||
if (!buffer.write(m_region->vaddr().offset(start).as_ptr(), num_bytes))
|
||||
return EIO;
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
KResultOr<PhysicalAddress> RingBuffer::reserve_space(size_t size)
|
||||
{
|
||||
if (m_capacity_in_bytes < m_num_used_bytes + size)
|
||||
return ENOSPC;
|
||||
size_t start_of_free_area = (m_start_of_used + m_num_used_bytes) % m_capacity_in_bytes;
|
||||
m_num_used_bytes += size;
|
||||
PhysicalAddress start_of_reserved_space = m_region->physical_page(start_of_free_area / PAGE_SIZE)->paddr().offset(start_of_free_area % PAGE_SIZE);
|
||||
return start_of_reserved_space;
|
||||
}
|
||||
|
||||
void RingBuffer::reclaim_space(PhysicalAddress chunk_start, size_t chunk_size)
|
||||
{
|
||||
VERIFY(start_of_used() == chunk_start);
|
||||
|
|
|
@ -17,10 +17,14 @@ public:
|
|||
|
||||
bool has_space() const { return m_num_used_bytes < m_capacity_in_bytes; }
|
||||
bool copy_data_in(const UserOrKernelBuffer& buffer, size_t offset, size_t length, PhysicalAddress& start_of_copied_data, size_t& bytes_copied);
|
||||
KResultOr<size_t> copy_data_out(size_t size, UserOrKernelBuffer& buffer) const;
|
||||
KResultOr<PhysicalAddress> reserve_space(size_t size);
|
||||
void reclaim_space(PhysicalAddress chunk_start, size_t chunk_size);
|
||||
PhysicalAddress start_of_used() const;
|
||||
|
||||
SpinLock<u8>& lock() { return m_lock; }
|
||||
size_t used_bytes() const { return m_num_used_bytes; }
|
||||
PhysicalAddress start_of_region() const { return m_region->physical_page(0)->paddr(); }
|
||||
|
||||
private:
|
||||
OwnPtr<Region> m_region;
|
||||
|
|
|
@ -43,6 +43,8 @@ UNMAP_AFTER_INIT VirtIOConsole::VirtIOConsole(PCI::Address address)
|
|||
finish_init();
|
||||
m_receive_buffer = make<RingBuffer>("VirtIOConsole Receive", RINGBUFFER_SIZE);
|
||||
m_transmit_buffer = make<RingBuffer>("VirtIOConsole Transmit", RINGBUFFER_SIZE);
|
||||
|
||||
init_receive_buffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +53,18 @@ VirtIOConsole::~VirtIOConsole()
|
|||
{
|
||||
}
|
||||
|
||||
void VirtIOConsole::init_receive_buffer()
|
||||
{
|
||||
auto& queue = get_queue(RECEIVEQ);
|
||||
ScopedSpinLock queue_lock(queue.lock());
|
||||
VirtIOQueueChain chain(queue);
|
||||
|
||||
auto buffer_start = m_receive_buffer->start_of_region();
|
||||
auto did_add_buffer = chain.add_buffer_to_chain(buffer_start, RINGBUFFER_SIZE, BufferType::DeviceWritable);
|
||||
VERIFY(did_add_buffer);
|
||||
supply_chain_and_notify(RECEIVEQ, chain);
|
||||
}
|
||||
|
||||
bool VirtIOConsole::handle_device_config_change()
|
||||
{
|
||||
dbgln("VirtIOConsole: Handle device config change");
|
||||
|
@ -63,8 +77,27 @@ void VirtIOConsole::handle_queue_update(u16 queue_index)
|
|||
VERIFY(queue_index <= TRANSMITQ);
|
||||
switch (queue_index) {
|
||||
case RECEIVEQ: {
|
||||
ScopedSpinLock lock(get_queue(RECEIVEQ).lock());
|
||||
get_queue(RECEIVEQ).discard_used_buffers(); // TODO: do something with incoming data (users writing into qemu console) instead of just clearing
|
||||
auto& queue = get_queue(RECEIVEQ);
|
||||
ScopedSpinLock queue_lock(queue.lock());
|
||||
size_t used;
|
||||
VirtIOQueueChain popped_chain = queue.pop_used_buffer_chain(used);
|
||||
|
||||
ScopedSpinLock ringbuffer_lock(m_receive_buffer->lock());
|
||||
|
||||
auto used_space = m_receive_buffer->reserve_space(used).value();
|
||||
auto remaining_space = RINGBUFFER_SIZE - used;
|
||||
|
||||
// Our algorithm always has only one buffer in the queue.
|
||||
VERIFY(!queue.new_data_available());
|
||||
popped_chain.release_buffer_slots_to_queue();
|
||||
|
||||
VirtIOQueueChain new_chain(queue);
|
||||
if (remaining_space != 0) {
|
||||
new_chain.add_buffer_to_chain(used_space.offset(used), remaining_space, BufferType::DeviceWritable);
|
||||
supply_chain_and_notify(RECEIVEQ, new_chain);
|
||||
}
|
||||
|
||||
evaluate_block_conditions();
|
||||
break;
|
||||
}
|
||||
case TRANSMITQ: {
|
||||
|
@ -91,12 +124,23 @@ void VirtIOConsole::handle_queue_update(u16 queue_index)
|
|||
|
||||
bool VirtIOConsole::can_read(const FileDescription&, size_t) const
|
||||
{
|
||||
return true;
|
||||
return m_receive_buffer->used_bytes() > 0;
|
||||
}
|
||||
|
||||
KResultOr<size_t> VirtIOConsole::read(FileDescription&, u64, [[maybe_unused]] UserOrKernelBuffer& data, size_t)
|
||||
KResultOr<size_t> VirtIOConsole::read(FileDescription& desc, u64, UserOrKernelBuffer& buffer, size_t size)
|
||||
{
|
||||
return ENOTSUP;
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if (!can_read(desc, size))
|
||||
return EAGAIN;
|
||||
|
||||
ScopedSpinLock ringbuffer_lock(m_receive_buffer->lock());
|
||||
|
||||
auto bytes_copied = m_receive_buffer->copy_data_out(size, buffer);
|
||||
m_receive_buffer->reclaim_space(m_receive_buffer->start_of_used(), bytes_copied.value());
|
||||
|
||||
return bytes_copied;
|
||||
}
|
||||
|
||||
bool VirtIOConsole::can_write(const FileDescription&, size_t) const
|
||||
|
|
|
@ -42,6 +42,8 @@ private:
|
|||
virtual String device_name() const override { return String::formatted("hvc{}", minor()); }
|
||||
virtual void handle_queue_update(u16 queue_index) override;
|
||||
|
||||
void init_receive_buffer();
|
||||
|
||||
OwnPtr<RingBuffer> m_receive_buffer;
|
||||
OwnPtr<RingBuffer> m_transmit_buffer;
|
||||
|
||||
|
|
Loading…
Reference in a new issue