blob: 8534919a309ef8eec1afdf0db6b5820d7c1204fb [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "linker.h"
30#include "linker_debug.h"
31#include "ba.h"
32
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080033#undef min
34#define min(a,b) ((a)<(b)?(a):(b))
35
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070036#define BA_IS_FREE(index) (!(ba->bitmap[index].allocated))
37#define BA_ORDER(index) ba->bitmap[index].order
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038#define BA_BUDDY_INDEX(index) ((index) ^ (1 << BA_ORDER(index)))
39#define BA_NEXT_INDEX(index) ((index) + (1 << BA_ORDER(index)))
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070040#define BA_OFFSET(index) ((index) * ba->min_alloc)
41#define BA_START_ADDR(index) (BA_OFFSET(index) + ba->base)
42#define BA_LEN(index) ((1 << BA_ORDER(index)) * ba->min_alloc)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080043
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070044void ba_init(struct ba *ba)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080045{
46 int i, index = 0;
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070047 for (i = sizeof(ba->num_entries) * 8 - 1; i >= 0; i--) {
48 if (ba->num_entries & 1<<i) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080049 BA_ORDER(index) = i;
50 index = BA_NEXT_INDEX(index);
51 }
52 }
53}
54
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070055int ba_free(struct ba *ba, int index)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080056{
57 int buddy, curr = index;
58
59 /* clean up the bitmap, merging any buddies */
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070060 ba->bitmap[curr].allocated = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080061 /* find a slots buddy Buddy# = Slot# ^ (1 << order)
62 * if the buddy is also free merge them
63 * repeat until the buddy is not free or end of the bitmap is reached
64 */
65 do {
66 buddy = BA_BUDDY_INDEX(curr);
67 if (BA_IS_FREE(buddy) &&
68 BA_ORDER(buddy) == BA_ORDER(curr)) {
69 BA_ORDER(buddy)++;
70 BA_ORDER(curr)++;
71 curr = min(buddy, curr);
72 } else {
73 break;
74 }
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070075 } while (curr < ba->num_entries);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080076
77 return 0;
78}
79
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070080static unsigned long ba_order(struct ba *ba, unsigned long len)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081{
82 unsigned long i;
83
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070084 len = (len + ba->min_alloc - 1) / ba->min_alloc;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080085 len--;
86 for (i = 0; i < sizeof(len)*8; i++)
87 if (len >> i == 0)
88 break;
89 return i;
90}
91
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070092int ba_allocate(struct ba *ba, unsigned long len)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093{
94 int curr = 0;
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070095 int end = ba->num_entries;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080096 int best_fit = -1;
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070097 unsigned long order = ba_order(ba, len);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080098
Iliyan Malchevaf7315a2009-10-16 17:50:42 -070099 if (order > ba->max_order)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800100 return -1;
101
102 /* look through the bitmap:
103 * if you find a free slot of the correct order use it
104 * otherwise, use the best fit (smallest with size > order) slot
105 */
106 while (curr < end) {
107 if (BA_IS_FREE(curr)) {
108 if (BA_ORDER(curr) == (unsigned char)order) {
109 /* set the not free bit and clear others */
110 best_fit = curr;
111 break;
112 }
113 if (BA_ORDER(curr) > (unsigned char)order &&
114 (best_fit < 0 ||
115 BA_ORDER(curr) < BA_ORDER(best_fit)))
116 best_fit = curr;
117 }
118 curr = BA_NEXT_INDEX(curr);
119 }
120
121 /* if best_fit < 0, there are no suitable slots,
122 * return an error
123 */
124 if (best_fit < 0)
125 return -1;
126
127 /* now partition the best fit:
128 * split the slot into 2 buddies of order - 1
129 * repeat until the slot is of the correct order
130 */
131 while (BA_ORDER(best_fit) > (unsigned char)order) {
132 int buddy;
133 BA_ORDER(best_fit) -= 1;
134 buddy = BA_BUDDY_INDEX(best_fit);
135 BA_ORDER(buddy) = BA_ORDER(best_fit);
136 }
Iliyan Malchevaf7315a2009-10-16 17:50:42 -0700137 ba->bitmap[best_fit].allocated = 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800138 return best_fit;
139}
140
Iliyan Malchevaf7315a2009-10-16 17:50:42 -0700141unsigned long ba_start_addr(struct ba *ba, int index)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800142{
143 return BA_START_ADDR(index);
144}
145
Iliyan Malchevaf7315a2009-10-16 17:50:42 -0700146unsigned long ba_len(struct ba *ba, int index)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800147{
148 return BA_LEN(index);
149}