3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/Log.h"
5#include "pedigree/kernel/panic.h"
6#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
7#include "pedigree/kernel/processor/VirtualAddressSpace.h"
8#include "pedigree/kernel/utilities/utility.h"
12using namespace Virtio;
15 : m_Descriptors(
"virtio descriptors"),
16 m_Available(
"virtio available ring"),
17 m_Used(
"virtio used ring"),
33 if (m_Attached || m_DmaArmed) {
34 panic(
"virtio: queue freed before transport reset");
38bool Queue::initialise(uint16_t depth,
PciTransport* transport) {
39 if (m_Online || m_DmaArmed || !transport || depth < 2 || depth > MaxDepth ||
57 for (uint16_t i = 0; i < depth; ++i)
58 m_Next[i] = i + 1 == depth ? Invalid : i + 1;
59 m_Transport = transport;
64bool Queue::submit(
const Buffer* buffers,
size_t count,
void* cookie) {
65 if (!buffers || !count || count > MaxDepth) {
69 if (!m_Online || count > m_FreeCount) {
72 for (
size_t i = 0; i < count; ++i) {
73 if (!buffers[i].address || !buffers[i].length ||
74 buffers[i].address + buffers[i].length < buffers[i].address) {
78 auto* descriptors =
static_cast<Descriptor*
>(m_Descriptors.
virtualAddress());
79 const uint16_t head = m_FreeHead;
80 uint16_t current = head;
81 for (
size_t i = 0; i < count; ++i) {
82 const uint16_t next = m_Next[current];
83 descriptors[current].address = buffers[i].address;
84 descriptors[current].length = buffers[i].length;
85 descriptors[current].flags = (i + 1 < count ? 1U : 0U) | (buffers[i].deviceWrites ? 2U : 0U);
86 descriptors[current].next = i + 1 < count ? next : 0;
91 m_ChainLength[head] = count;
92 m_Cookies[head] = cookie;
93 m_Active[head] =
true;
94 auto* available =
static_cast<volatile uint16_t*
>(m_Available.
virtualAddress());
95 available[2 + (m_AvailableIndex % m_Depth)] = head;
97 available[1] = ++m_AvailableIndex;
107 auto* usedIndex =
static_cast<volatile uint16_t*
>(m_Used.
virtualAddress());
108 const uint16_t available = usedIndex[1];
109 if (available == m_UsedIndex) {
112 if (
static_cast<uint16_t
>(available - m_UsedIndex) > m_Depth) {
113 ERROR(
"virtio: invalid used-ring index");
118 auto* entries =
static_cast<volatile uint32_t*
>(m_Used.
virtualAddress());
119 const size_t slot = m_UsedIndex % m_Depth;
120 const uint32_t
id = entries[1 + slot * 2];
121 const uint32_t length = entries[2 + slot * 2];
122 if (
id >= m_Depth || !m_Active[
id] || !m_ChainLength[
id]) {
123 ERROR(
"virtio: invalid used-ring descriptor");
127 completion.cookie = m_Cookies[id];
128 completion.length = length;
129 m_Cookies[id] =
nullptr;
130 m_Active[id] =
false;
131 uint16_t current = id;
132 for (uint16_t i = 0; i < m_ChainLength[id]; ++i) {
133 const uint16_t next = m_Next[current];
134 m_Next[current] = m_FreeHead;
135 m_FreeHead = current;
138 m_FreeCount += m_ChainLength[id];
139 m_ChainLength[id] = 0;
void * virtualAddress() const
static const size_t continuous
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
static const size_t KernelMode
static const size_t Write
void EXPORTED_PUBLIC panic(const char *msg) NORETURN