• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
33 struct ba_bits {
34     unsigned allocated:1;           /* 1 if allocated, 0 if free */
35     unsigned order:7;               /* size of the region in ba space */
36 };
37 
38 struct ba_info {
39     /* start address of the ba space */
40     unsigned long base;
41     /* total size of the ba space */
42     unsigned long size;
43     /* number of entries in the ba space */
44     int num_entries;
45     /* the bitmap for the region indicating which entries are allocated
46      * and which are free */
47     struct ba_bits *bitmap;
48 };
49 
50 #undef min
51 #define min(a,b) ((a)<(b)?(a):(b))
52 
53 #define BA_MIN_ALLOC LIBINC
54 #define BA_MAX_ORDER 128
55 #define BA_START LIBBASE
56 #define BA_SIZE (LIBLAST - LIBBASE)
57 
58 #define BA_IS_FREE(index) (!(ba.bitmap[index].allocated))
59 #define BA_ORDER(index) ba.bitmap[index].order
60 #define BA_BUDDY_INDEX(index) ((index) ^ (1 << BA_ORDER(index)))
61 #define BA_NEXT_INDEX(index) ((index) + (1 << BA_ORDER(index)))
62 #define BA_OFFSET(index) ((index) * BA_MIN_ALLOC)
63 #define BA_START_ADDR(index) (BA_OFFSET(index) + ba.base)
64 #define BA_LEN(index) ((1 << BA_ORDER(index)) * BA_MIN_ALLOC)
65 
66 static struct ba_bits ba_bitmap[BA_SIZE / BA_MIN_ALLOC];
67 
68 static struct ba_info ba = {
69     .base = BA_START,
70     .size = BA_SIZE,
71     .bitmap = ba_bitmap,
72     .num_entries = sizeof(ba_bitmap)/sizeof(ba_bitmap[0]),
73 };
74 
ba_init(void)75 void ba_init(void)
76 {
77     int i, index = 0;
78     for (i = sizeof(ba.num_entries) * 8 - 1; i >= 0; i--) {
79         if (ba.num_entries &  1<<i) {
80             BA_ORDER(index) = i;
81             index = BA_NEXT_INDEX(index);
82         }
83     }
84 }
85 
ba_free(int index)86 int ba_free(int index)
87 {
88     int buddy, curr = index;
89 
90     /* clean up the bitmap, merging any buddies */
91     ba.bitmap[curr].allocated = 0;
92     /* find a slots buddy Buddy# = Slot# ^ (1 << order)
93      * if the buddy is also free merge them
94      * repeat until the buddy is not free or end of the bitmap is reached
95      */
96     do {
97         buddy = BA_BUDDY_INDEX(curr);
98         if (BA_IS_FREE(buddy) &&
99                 BA_ORDER(buddy) == BA_ORDER(curr)) {
100             BA_ORDER(buddy)++;
101             BA_ORDER(curr)++;
102             curr = min(buddy, curr);
103         } else {
104             break;
105         }
106     } while (curr < ba.num_entries);
107 
108     return 0;
109 }
110 
ba_order(unsigned long len)111 static unsigned long ba_order(unsigned long len)
112 {
113     unsigned long i;
114 
115     len = (len + BA_MIN_ALLOC - 1) / BA_MIN_ALLOC;
116     len--;
117     for (i = 0; i < sizeof(len)*8; i++)
118         if (len >> i == 0)
119             break;
120     return i;
121 }
122 
ba_allocate(unsigned long len)123 int ba_allocate(unsigned long len)
124 {
125     int curr = 0;
126     int end = ba.num_entries;
127     int best_fit = -1;
128     unsigned long order = ba_order(len);
129 
130     if (order > BA_MAX_ORDER)
131         return -1;
132 
133     /* look through the bitmap:
134      *  if you find a free slot of the correct order use it
135      *  otherwise, use the best fit (smallest with size > order) slot
136      */
137     while (curr < end) {
138         if (BA_IS_FREE(curr)) {
139             if (BA_ORDER(curr) == (unsigned char)order) {
140                 /* set the not free bit and clear others */
141                 best_fit = curr;
142                 break;
143             }
144             if (BA_ORDER(curr) > (unsigned char)order &&
145                 (best_fit < 0 ||
146                  BA_ORDER(curr) < BA_ORDER(best_fit)))
147                 best_fit = curr;
148         }
149         curr = BA_NEXT_INDEX(curr);
150     }
151 
152     /* if best_fit < 0, there are no suitable slots,
153      * return an error
154      */
155     if (best_fit < 0)
156         return -1;
157 
158     /* now partition the best fit:
159      *  split the slot into 2 buddies of order - 1
160      *  repeat until the slot is of the correct order
161      */
162     while (BA_ORDER(best_fit) > (unsigned char)order) {
163         int buddy;
164         BA_ORDER(best_fit) -= 1;
165         buddy = BA_BUDDY_INDEX(best_fit);
166         BA_ORDER(buddy) = BA_ORDER(best_fit);
167     }
168     ba.bitmap[best_fit].allocated = 1;
169     return best_fit;
170 }
171 
ba_start_addr(int index)172 unsigned long ba_start_addr(int index)
173 {
174     return BA_START_ADDR(index);
175 }
176 
ba_len(int index)177 unsigned long ba_len(int index)
178 {
179     return BA_LEN(index);
180 }
181