13 __extension__ __auto_type _x = (x); \
14 _x ? (sizeof(_x) * 8 - 1 - __builtin_clzl(_x)) : 0; \
16#define log2_ceil(x) (log2(x) + (pow2(log2(x)) < x))
18static 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 };
33 list_node_t *frame_node =
list_node(frame);
40 while (node != head && node < frame_node)
49 return page_pfn ^
pow2(order);
56 pr_cont(
"\nlist of order %zu: ", order);
74static void populate_freelist(
const size_t start_pfn,
const size_t nframes,
const size_t order)
78 const size_t step =
pow2(order);
80 pr_dinfo2(pmm_buddy,
" order: %zu, step: %zu", order, step);
83 size_t nframes_left = nframes;
89 frame->
state = PHYFRAME_FREE;
111 const pfn_t frame2_pfn = this_pfn +
pow2(this_order - 1);
113 frame2_pfn - 1, frame2_pfn, frame2_pfn +
pow2(this_order - 1) - 1);
127 size_t last_nframes = 0;
131 if (last_nframes == nframes)
134 if (state == PHYFRAME_RESERVED && frame->
state == PHYFRAME_RESERVED)
147 last_nframes = nframes;
150 pr_dinfo2(pmm_buddy,
" extracting, n left: %zu, start: " PFN_FMT, nframes, start);
162 const pfn_t end_pfn = start_pfn +
pow2(order) - 1;
164 if (start_pfn == start)
172 pr_dinfo2(pmm_buddy,
" found a frame that starts with " PFN_FMT "...", start);
173 if (
pow2(order) <= nframes)
179 nframes -=
pow2(order);
180 start +=
pow2(order);
182 pr_dinfo2(pmm_buddy,
" done, n left: %zu, start: " PFN_FMT, nframes, start);
187 pr_dinfo2(pmm_buddy,
" narrowing down...");
195 if (start_pfn <= start && end_pfn >= start)
227 pr_dinfo2(pmm_buddy,
" no free frames of order %zu, can't break", order);
236 const pfn_t frame2_pfn = frame_pfn +
pow2(order - 1);
239 frame2_pfn, frame2_pfn +
pow2(order - 1) - 1);
243 frame2->
state = PHYFRAME_FREE;
261 pr_dinfo2(pmm_buddy,
" order %hhu is too large, cannot merge", order);
272 if (
buddy->state != PHYFRAME_FREE)
278 if (
buddy->order != order)
280 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);
285 frame->
state = PHYFRAME_FREE;
289 const size_t high_order_pfn =
MIN(pfn, buddy_pfn);
291 if (!
try_merge(high_order_pfn, order + 1))
295 high_order_frame->
state = PHYFRAME_FREE;
326 pr_dinfo2(pmm_buddy,
"reserving " PFN_RANGE " (%zu frames)", pfn, pfn + nframes - 1, nframes);
340 pr_dinfo2(pmm_buddy,
"allocating %zu contiguous frames (order %zu, which is %zu frames, wasting %zu frames)", nframes, order,
pow2(order),
pow2(order) - nframes);
349 pr_emerg(
"no free frames of order %zu, can't break", order);
359 for (
size_t i = 0; i < nframes; i++)
362 f->
state = PHYFRAME_ALLOCATED;
372 pr_dinfo2(pmm_buddy,
"freeing " PFN_RANGE " (%zu frames)", pfn, pfn + nframes - 1, nframes);
378 frame->
state = 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 dump_list(size_t order)
void buddy_dump_all()
Dump the state of the buddy allocator.
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 void extract_exact_range(pfn_t start, size_t nframes, enum phyframe_state state)
static const size_t max_order
void buddy_free_n(pfn_t pfn, size_t nframes)
Free nframes of contiguous physical memory.
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