13constexpr size_t pow2(
size_t x)
18constexpr size_t log2(
size_t x)
20 return x ? (
sizeof(x) * 8 - 1 - __builtin_clzl(x)) : 0;
23#define log2_ceil(x) (log2(x) + (pow2(log2(x)) < x))
25static const size_t orders[] = { 0, 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 };
47 while (node != head && node < frame_node)
56 return page_pfn ^
pow2(order);
63 pr_cont(
"\nlist of order %zu: ", order);
83static void populate_freelist(
const size_t start_pfn,
const size_t nframes,
const size_t order)
87 const size_t step =
pow2(order);
89 pr_dinfo2(pmm_buddy,
" order: %zu, step: %zu", order, step);
92 size_t nframes_left = nframes;
98 frame->
state = phyframe::PHYFRAME_FREE;
101 frame->
order = order;
103 nframes_left -= step;
120 const pfn_t frame2_pfn = this_pfn +
pow2(this_order - 1);
122 frame2_pfn - 1, frame2_pfn, frame2_pfn +
pow2(this_order - 1) - 1);
136 size_t last_nframes = 0;
140 if (last_nframes == nframes)
143 if (state == phyframe::PHYFRAME_RESERVED && frame->
state == phyframe::PHYFRAME_RESERVED)
156 last_nframes = nframes;
159 pr_dinfo2(pmm_buddy,
" extracting, n left: %zu, start: " PFN_FMT, nframes, start);
168 list_foreach(phyframe_t::additional_info, info, *freelist)
172 const pfn_t end_pfn = start_pfn +
pow2(order) - 1;
174 if (start_pfn == start)
182 pr_dinfo2(pmm_buddy,
" found a frame that starts with " PFN_FMT "...", start);
183 if (
pow2(order) <= nframes)
189 nframes -=
pow2(order);
190 start +=
pow2(order);
192 pr_dinfo2(pmm_buddy,
" done, n left: %zu, start: " PFN_FMT, nframes, start);
197 pr_dinfo2(pmm_buddy,
" narrowing down...");
205 if (start_pfn <= start && end_pfn >= start)
237 pr_dinfo2(pmm_buddy,
" no free frames of order %zu, can't break", order);
241 const auto info =
list_entry(freelist->next, phyframe_t::additional_info);
243 MOS_ASSERT(frame->state == phyframe::PHYFRAME_FREE);
247 const pfn_t frame2_pfn = frame_pfn +
pow2(order - 1);
250 frame2_pfn, frame2_pfn +
pow2(order - 1) - 1);
254 frame2->
state = phyframe::PHYFRAME_FREE;
272 pr_dinfo2(pmm_buddy,
" order %hhu is too large, cannot merge", order);
283 if (
buddy->state != phyframe::PHYFRAME_FREE)
289 if (
buddy->order != order)
291 pr_dinfo2(pmm_buddy,
" buddy pfn " PFN_FMT " is not the same order (%hhu != %hhu) as " PFN_FMT ", not merging", buddy_pfn,
buddy->order, order, pfn);
296 frame->
state = phyframe::PHYFRAME_FREE;
300 const size_t high_order_pfn = std::min(pfn, buddy_pfn);
302 if (!
try_merge(high_order_pfn, order + 1))
306 high_order_frame->
state = phyframe::PHYFRAME_FREE;
337 pr_dinfo2(pmm_buddy,
"reserving " PFN_RANGE " (%zu frames)", pfn, pfn + nframes - 1, nframes);
351 pr_dinfo2(pmm_buddy,
"allocating %zu contiguous frames (order %zu, which is %zu frames, wasting %zu frames)", nframes, order,
pow2(order),
pow2(order) - nframes);
360 pr_emerg(
"no free frames of order %zu, can't break", order);
370 for (
size_t i = 0; i < nframes; i++)
373 f->
state = phyframe::PHYFRAME_ALLOCATED;
383 pr_dinfo2(pmm_buddy,
"freeing " PFN_RANGE " (%zu frames)", pfn, pfn + nframes - 1, nframes);
387 MOS_ASSERT_X(frame->
state == phyframe::PHYFRAME_ALLOCATED,
"frame must be allocated");
389 frame->
state = phyframe::PHYFRAME_FREE;
#define MOS_ASSERT_X(cond, msg,...)
static bool try_merge(const pfn_t pfn, u8 order)
Try finding a buddy frame and merging it with the given frame.
phyframe_t * buddy_alloc_n_exact(size_t nframes)
Allocate nframes of contiguous physical memory.
static const size_t orders[]
static void break_the_order(const size_t order)
static void extract_exact_range(pfn_t start, size_t nframes, enum phyframe::phyframe_state state)
static void dump_list(size_t order)
static struct @157025346226044251143103256261246056252331122177 buddy
void buddy_dump_all()
Dump the state of the buddy allocator.
constexpr size_t log2(size_t x)
list_head freelists[MOS_ARRAY_SIZE(orders)]
static void populate_freelist(const size_t start_pfn, const size_t nframes, const size_t order)
Add [start_pfn, start_pfn + nframes - 1] to the freelist of order order
static pfn_t get_buddy_pfn(size_t page_pfn, size_t order)
static const size_t max_order
void buddy_free_n(pfn_t pfn, size_t nframes)
Free nframes of contiguous physical memory.
constexpr size_t pow2(size_t x)
static void add_to_freelist(size_t order, phyframe_t *frame)
void buddy_init(size_t max_nframes)
Initialize the buddy allocator with the given maximum number of frames.
static void break_this_pfn(pfn_t this_pfn, size_t this_order)
void buddy_reserve_n(pfn_t pfn, size_t nframes)
Reserve several frames at the given physical frame number.
static spinlock_t buddy_lock
MOSAPI void linked_list_init(list_node_t *head_node)
Initialise a circular double linked list.
MOSAPI void list_node_insert_before(list_node_t *element, list_node_t *item)
#define list_foreach(t, v, h)
Iterate over a list.
#define list_node(element)
Get the ‘list_node’ of a list element. This is exactly the reverse of ‘list_entry’ above.
#define list_entry(node, type)
Get the container struct of a list node.
list_node_t list_head
A linked list head.
MOSAPI bool list_is_empty(const list_node_t *head)
#define list_remove(element)
#define pfn_phyframe(pfn)
#define phyframe_pfn(frame)
#define MOS_ARRAY_SIZE(x)
#define mos_panic(fmt,...)
#define pr_emerg(fmt,...)
#define pr_dinfo2(feat, fmt,...)
should_inline bool spinlock_is_locked(const spinlock_t *lock)
#define spinlock_acquire(lock)
#define spinlock_release(lock)
enum phyframe_t::phyframe_state state
union phyframe_t::additional_info info
#define container_of(ptr, type, member)