diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 46e306fa..15562d8f 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -50,6 +50,7 @@ set(KERNEL_SOURCES kernel/InterruptController.cpp kernel/kernel.cpp kernel/Lock/SpinLock.cpp + kernel/Memory/ByteRingBuffer.cpp kernel/Memory/DMARegion.cpp kernel/Memory/FileBackedRegion.cpp kernel/Memory/Heap.cpp diff --git a/kernel/include/kernel/Memory/ByteRingBuffer.h b/kernel/include/kernel/Memory/ByteRingBuffer.h new file mode 100644 index 00000000..c3abcad4 --- /dev/null +++ b/kernel/include/kernel/Memory/ByteRingBuffer.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include + +#include + +namespace Kernel +{ + + class ByteRingBuffer + { + public: + static BAN::ErrorOr> create(size_t size); + ~ByteRingBuffer(); + + void push(BAN::ConstByteSpan data) + { + ASSERT(data.size() + m_size <= m_capacity); + uint8_t* buffer_head = reinterpret_cast(m_vaddr) + (m_tail + m_size) % m_capacity; + memcpy(buffer_head, data.data(), data.size()); + m_size += data.size(); + } + + void pop(size_t size) + { + ASSERT(size <= m_size); + m_tail = (m_tail + size) % m_capacity; + m_size -= size; + } + + BAN::ConstByteSpan get_data() const + { + const uint8_t* base = reinterpret_cast(m_vaddr); + return { base + m_tail, m_size }; + } + + bool empty() const { return m_size == 0; } + bool full() const { return m_size == m_capacity; } + size_t free() const { return m_capacity - m_size; } + size_t size() const { return m_size; } + size_t capacity() const { return m_capacity; } + + private: + ByteRingBuffer(size_t capacity) + : m_capacity(capacity) + { } + + private: + size_t m_size { 0 }; + size_t m_tail { 0 }; + const size_t m_capacity; + + vaddr_t m_vaddr { 0 }; + }; + +} diff --git a/kernel/kernel/Memory/ByteRingBuffer.cpp b/kernel/kernel/Memory/ByteRingBuffer.cpp new file mode 100644 index 00000000..24eb3274 --- /dev/null +++ b/kernel/kernel/Memory/ByteRingBuffer.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +namespace Kernel +{ + + BAN::ErrorOr> ByteRingBuffer::create(size_t size) + { + ASSERT(size % PAGE_SIZE == 0); + + const size_t page_count = size / PAGE_SIZE; + + auto* buffer_ptr = new ByteRingBuffer(size); + if (buffer_ptr == nullptr) + return BAN::Error::from_errno(ENOMEM); + auto buffer = BAN::UniqPtr::adopt(buffer_ptr); + + buffer->m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(page_count * 2, KERNEL_OFFSET); + if (buffer->m_vaddr == 0) + return BAN::Error::from_errno(ENOMEM); + + for (size_t i = 0; i < page_count; i++) + { + const paddr_t paddr = Heap::get().take_free_page(); + if (paddr == 0) + return BAN::Error::from_errno(ENOMEM); + PageTable::kernel().map_page_at(paddr, buffer->m_vaddr + i * PAGE_SIZE, PageTable::ReadWrite | PageTable::Present); + PageTable::kernel().map_page_at(paddr, buffer->m_vaddr + size + i * PAGE_SIZE, PageTable::ReadWrite | PageTable::Present); + } + + return buffer; + } + + ByteRingBuffer::~ByteRingBuffer() + { + if (m_vaddr == 0) + return; + for (size_t i = 0; i < m_capacity / PAGE_SIZE; i++) + { + const paddr_t paddr = PageTable::kernel().physical_address_of(m_vaddr + i * PAGE_SIZE); + if (paddr == 0) + break; + Heap::get().release_page(paddr); + } + PageTable::kernel().unmap_range(m_vaddr, m_capacity * 2); + } + +}