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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#include "kernel/memory/mmio_allocator.hpp"
#include "kapi/memory.hpp"
#include "kapi/system.hpp"
#include <kstd/allocator>
#include <cstddef>
#include <memory>
#include <utility>
namespace kernel::memory
{
mmio_allocator::mmio_allocator(kapi::memory::linear_address base, std::size_t pages)
: m_head{make_node(base, pages, nullptr, nullptr, true)}
{}
auto mmio_allocator::allocate(std::size_t count) -> kapi::memory::linear_address
{
if (count == 0 || !m_head)
{
return {};
}
auto current = m_head;
while (current)
{
if (current->is_free && current->page_count >= count)
{
if (current->page_count > count)
{
auto new_base = current->base + (count * kapi::memory::page::size);
auto split_node = make_node(new_base, current->page_count - count, std::move(current->next), current, true);
if (current->next)
{
current->next->previous = split_node;
}
current->next = split_node;
current->page_count = count;
}
current->is_free = false;
return current->base;
}
current = current->next;
}
kapi::system::panic("[OS:MEM] MMIO alloctor out of memory!");
return {};
}
auto mmio_allocator::release(kapi::memory::linear_address base) -> void
{
auto current = m_head;
while (current)
{
if (current->base == base && !current->is_free)
{
current->is_free = true;
if (current->next && current->next->is_free)
{
auto removed = current->next;
current->page_count += removed->page_count;
current->next = removed->next;
if (current->next)
{
current->next->previous = current;
}
destroy_node(removed);
}
if (current->previous && current->previous->is_free)
{
auto removed = current;
removed->previous->page_count += removed->page_count;
removed->previous->next = removed->next;
if (removed->next)
{
removed->next->previous = removed->previous;
}
destroy_node(removed);
}
return;
}
current = current->next;
}
}
auto mmio_allocator::make_node(kapi::memory::linear_address base, std::size_t page_count, node * next,
node * previous, bool is_free) -> node *
{
using traits = std::allocator_traits<kstd::allocator<node>>;
auto new_node = traits::allocate(m_allocator, 1);
traits::construct(m_allocator, new_node, base, page_count, next, previous, is_free);
return new_node;
}
auto mmio_allocator::destroy_node(node * instance) -> void
{
using traits = std::allocator_traits<kstd::allocator<node>>;
traits::destroy(m_allocator, instance);
traits::deallocate(m_allocator, instance, 1);
}
} // namespace kernel::memory
|