26 next->prev_next = prev_next;
30 static void link(Head **h, void *b, unsigned idx)
37 (*h)->prev_next = &(n->next);
43 template< int MIN_LOG2_SIZE, int NUM_SIZES, int MAX_MEM >
44 class Buddy_t_base : public Buddy_base
49 Min_log2_size = MIN_LOG2_SIZE,
50 Min_size = 1UL << MIN_LOG2_SIZE,
51 Num_sizes = NUM_SIZES,
52 Max_size = Min_size << NUM_SIZES,
57 Head *_free[Num_sizes];
58 Bitmap<(Max_mem+Min_size-1)/Min_size> _free_map;
62 class Buddy_alloc : public Buddy_t_base<10, 8, Config::kernel_mem_max>
67 //----------------------------------------------------------------------------
76 template<int A, int B, int M>
79 Buddy_t_base<A,B,M>::buddy(void *block, unsigned long index, Head **new_block)
81 //printf("buddy(%p, %ld)\n", block, index);
82 unsigned long const size = Min_size << index;
83 unsigned long const n_size = size << 1;
84 if (index + 1 >= Num_sizes)
86 unsigned long b = (unsigned long)block;
87 unsigned long _buddy = b & ~(n_size-1);
88 *new_block = (Head*)_buddy;
92 Head * const _buddy_h = (Head*)_buddy;
94 if (_free_map[(_buddy - _base)/Min_size] && _buddy_h->index == index)
101 template<int A, int B, int M>
104 Buddy_t_base<A,B,M>::free(void *block, unsigned long size)
106 assert_kdb ((unsigned long)block >= _base);
107 assert_kdb ((unsigned long)block - _base < Max_mem);
108 assert_kdb (!_free_map[((unsigned long)block - _base) / Min_size]);
110 //if (_debug) printf("Buddy::free(%p, %ld)\n", block, size);
111 unsigned size_index = 0;
112 while (((unsigned long)Min_size << size_index) < size)
115 if (size != (unsigned long)Min_size << size_index)
116 WARNX(Info, "Buddy::free: Size mismatch: %lx v %lx\n",
117 size, (unsigned long)Min_size << size_index);
120 while (size_index < Num_sizes)
123 b = buddy(block, size_index, &n);
126 //if (!_b && _debug) dump();
127 //if (_debug) printf(" found buddy %p (n=%p size=%ld)\n", b, n, size_index+1);
137 //printf(" link free %p\n", block);
138 Head::link(_free + size_index, block, size_index);
139 _free_map.set_bit(((unsigned long)block - _base) / Min_size);
140 //if (_b && _debug) dump();
145 template<int A, int B, int M>
147 Buddy_t_base<A,B,M>::add_mem(void *b, unsigned long size)
149 unsigned long start = (unsigned long)b;
150 unsigned long al_start;
151 al_start = (start + Min_size - 1) & ~(Min_size -1);
153 //printf("Buddy::add_mem(%p, %lx): al_start=%lx; _base=%lx\n", b, size, al_start, _base);
156 if (size <= al_start-start)
159 size -= (al_start-start);
160 size &= ~(Min_size -1);
164 free((void*)al_start, Min_size);
165 al_start += Min_size;
175 template<int A, int B, int M>
178 Buddy_t_base<A,B,M>::split(Head *b, unsigned size_index, unsigned i)
180 //unsigned si = size_index;
181 //printf("Buddy::split(%p, %d, %d)\n", b, size_index, i);
182 for (; i > size_index; ++size_index)
184 unsigned long buddy = (unsigned long)b + (Min_size << size_index);
185 Head::link(_free + size_index, (void*)buddy, size_index);
186 _free_map.set_bit((buddy - _base) / Min_size);
193 template<int A, int B, int M>
196 Buddy_t_base<A,B,M>::alloc(unsigned long size)
198 unsigned size_index = 0;
199 while (((unsigned long)Min_size << size_index) < size)
202 if (size != (unsigned long)Min_size << size_index)
203 WARNX(Info, "Buddy::alloc: Size mismatch: %lx v %lx\n",
204 size, (unsigned long)Min_size << size_index);
206 //printf("[%u]: Buddy::alloc(%ld)[ret=%p]: size_index=%d\n", Proc::cpu_id(), size, __builtin_return_address(0), size_index);
208 for (unsigned i = size_index; i < Num_sizes; ++i)
214 split(f, size_index, i);
215 _free_map.clear_bit(((unsigned long)f - _base) / Min_size);
216 //printf("[%u]: =%p\n", Proc::cpu_id(), f);
224 template< int A, int B, int M >
226 Buddy_t_base<A,B,M>::dump() const
228 printf("Buddy_alloc [%d,%d]\n", Min_size, Num_sizes);
229 for (unsigned i = 0; i < Num_sizes; ++i)
233 printf(" [%d] %p(%ld)", Min_size << i, h, h?h->index:0UL);
238 printf(" -> %p(%ld)", h, h?h->index:0UL);
253 Buddy_base::init(unsigned long base)
257 template< int A, int B, int M >
259 Buddy_t_base<A,B,M>::avail() const
262 for (unsigned i = 0; i < Num_sizes; ++i)
267 a += (Min_size << i);