1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
/*
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <AK/Stack.h>
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Memory/Region.h>
#include <Kernel/StdLib.h>
namespace Kernel::USB {
// This pool is bound by PAGE_SIZE / sizeof(T). The underlying allocation for the pointers
// is AK::Stack. As such, we never dynamically allocate any memory past the amount
// that can fit in a single page.
template<typename T>
class UHCIDescriptorPool {
AK_MAKE_NONCOPYABLE(UHCIDescriptorPool);
AK_MAKE_NONMOVABLE(UHCIDescriptorPool);
// Ensure that we can't get into a situation where we'll write past the page
// and blow up
static_assert(sizeof(T) <= PAGE_SIZE);
public:
static KResultOr<NonnullOwnPtr<UHCIDescriptorPool<T>>> try_create(StringView name)
{
auto pool_memory_block = MM.allocate_kernel_region(PAGE_SIZE, "UHCI Descriptor Pool", Memory::Region::Access::ReadWrite);
if (!pool_memory_block)
return ENOMEM;
return adopt_nonnull_own_or_enomem(new (nothrow) UHCIDescriptorPool(pool_memory_block.release_nonnull(), name));
}
~UHCIDescriptorPool() = default;
[[nodiscard]] T* try_take_free_descriptor()
{
// We're out of descriptors!
if (m_free_descriptor_stack.is_empty())
return nullptr;
dbgln_if(UHCI_VERBOSE_DEBUG, "Got a free UHCI Descriptor @ {} from pool {}", m_free_descriptor_stack.top(), m_pool_name);
T* descriptor = m_free_descriptor_stack.top();
m_free_descriptor_stack.pop();
return descriptor;
}
void release_to_pool(T* ptr)
{
dbgln_if(UHCI_VERBOSE_DEBUG, "Returning descriptor @ {} to pool {}", ptr, m_pool_name);
if (!m_free_descriptor_stack.push(ptr))
dbgln("Failed to return descriptor to pool {}. Stack overflow!", m_pool_name);
}
void print_pool_information() const
{
dbgln("Pool {} allocated @ {}", m_pool_name, m_pool_region->physical_page(0)->paddr());
}
private:
UHCIDescriptorPool(NonnullOwnPtr<Memory::Region> pool_memory_block, StringView name)
: m_pool_name(name)
, m_pool_region(move(pool_memory_block))
{
// Go through the number of descriptors to create in the pool, and create a virtual/physical address mapping
for (size_t i = 0; i < PAGE_SIZE / sizeof(T); i++) {
auto placement_address = reinterpret_cast<void*>(m_pool_region->vaddr().get() + (i * sizeof(T)));
auto physical_address = static_cast<u32>(m_pool_region->physical_page(0)->paddr().get() + (i * sizeof(T)));
auto* object = new (placement_address) T(physical_address);
m_free_descriptor_stack.push(object); // Push the descriptor's pointer onto the free list
}
}
StringView m_pool_name; // Name of this pool
NonnullOwnPtr<Memory::Region> m_pool_region; // Memory region where descriptors actually reside
Stack<T*, PAGE_SIZE / sizeof(T)> m_free_descriptor_stack; // Stack of currently free descriptor pointers
};
}
|