4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/cmn_err.h>
28 #include <sys/mutex.h>
29 #include <sys/param.h> /* for NULL */
30 #include <sys/debug.h>
31 #include <sys/memlist.h>
32 #include <sys/memlist_impl.h>
34 static struct memlist
*memlist_freelist
;
35 static uint_t memlist_freelist_count
;
36 static kmutex_t memlist_freelist_mutex
;
39 * Caller must test for NULL return.
46 mutex_enter(&memlist_freelist_mutex
);
47 mlp
= memlist_freelist
;
49 memlist_freelist
= mlp
->ml_next
;
50 memlist_freelist_count
--;
52 mutex_exit(&memlist_freelist_mutex
);
58 memlist_free_one(struct memlist
*mlp
)
62 mutex_enter(&memlist_freelist_mutex
);
63 mlp
->ml_next
= memlist_freelist
;
64 memlist_freelist
= mlp
;
65 memlist_freelist_count
++;
66 mutex_exit(&memlist_freelist_mutex
);
70 memlist_free_list(struct memlist
*mlp
)
72 struct memlist
*mlendp
;
80 for (mlendp
= mlp
; mlendp
->ml_next
!= NULL
; mlendp
= mlendp
->ml_next
)
82 mutex_enter(&memlist_freelist_mutex
);
83 mlendp
->ml_next
= memlist_freelist
;
84 memlist_freelist
= mlp
;
85 memlist_freelist_count
+= count
;
86 mutex_exit(&memlist_freelist_mutex
);
90 memlist_free_block(caddr_t base
, size_t bytes
)
92 struct memlist
*mlp
, *mlendp
;
95 count
= bytes
/ sizeof (struct memlist
);
99 mlp
= (struct memlist
*)base
;
100 mlendp
= &mlp
[count
- 1];
101 for (; mlp
!= mlendp
; mlp
++)
102 mlp
->ml_next
= mlp
+ 1;
103 mlendp
->ml_next
= NULL
;
104 mlp
= (struct memlist
*)base
;
105 mutex_enter(&memlist_freelist_mutex
);
106 mlendp
->ml_next
= memlist_freelist
;
107 memlist_freelist
= mlp
;
108 memlist_freelist_count
+= count
;
109 mutex_exit(&memlist_freelist_mutex
);
113 * Insert into a sorted memory list.
114 * new = new element to insert
115 * curmemlistp = memory list to which to add segment.
120 struct memlist
**curmemlistp
)
122 struct memlist
*cur
, *last
;
125 start
= new->ml_address
;
126 end
= start
+ new->ml_size
;
128 for (cur
= *curmemlistp
; cur
; cur
= cur
->ml_next
) {
130 if (cur
->ml_address
>= end
) {
132 new->ml_prev
= cur
->ml_prev
;
134 if (cur
== *curmemlistp
)
137 new->ml_prev
->ml_next
= new;
140 if (cur
->ml_address
+ cur
->ml_size
> start
)
141 panic("munged memory list = 0x%p\n",
142 (void *)curmemlistp
);
151 memlist_del(struct memlist
*memlistp
,
152 struct memlist
**curmemlistp
)
156 * Check that the memlist is on the list.
160 for (mlp
= *curmemlistp
; mlp
!= NULL
; mlp
= mlp
->ml_next
)
163 ASSERT(mlp
== memlistp
);
165 if (*curmemlistp
== memlistp
) {
166 ASSERT(memlistp
->ml_prev
== NULL
);
167 *curmemlistp
= memlistp
->ml_next
;
169 if (memlistp
->ml_prev
!= NULL
) {
170 ASSERT(memlistp
->ml_prev
->ml_next
== memlistp
);
171 memlistp
->ml_prev
->ml_next
= memlistp
->ml_next
;
173 if (memlistp
->ml_next
!= NULL
) {
174 ASSERT(memlistp
->ml_next
->ml_prev
== memlistp
);
175 memlistp
->ml_next
->ml_prev
= memlistp
->ml_prev
;
180 memlist_find(struct memlist
*mlp
, uint64_t address
)
182 for (; mlp
!= NULL
; mlp
= mlp
->ml_next
)
183 if (address
>= mlp
->ml_address
&&
184 address
< (mlp
->ml_address
+ mlp
->ml_size
))
190 * Add a span to a memlist.
192 * MEML_SPANOP_OK if OK.
193 * MEML_SPANOP_ESPAN if part or all of span already exists
194 * MEML_SPANOP_EALLOC for allocation failure
200 struct memlist
**curmemlistp
)
203 struct memlist
*prev
, *next
;
206 * allocate a new struct memlist
209 dst
= memlist_get_one();
212 return (MEML_SPANOP_EALLOC
);
215 dst
->ml_address
= address
;
216 dst
->ml_size
= bytes
;
221 if (*curmemlistp
== NULL
) {
225 return (MEML_SPANOP_OK
);
229 * Insert into sorted list.
231 for (prev
= NULL
, next
= *curmemlistp
; next
!= NULL
;
232 prev
= next
, next
= next
->ml_next
) {
233 if (address
> (next
->ml_address
+ next
->ml_size
))
243 if ((address
+ bytes
) == next
->ml_address
) {
244 memlist_free_one(dst
);
246 next
->ml_address
= address
;
247 next
->ml_size
+= bytes
;
249 return (MEML_SPANOP_OK
);
255 if (address
== (next
->ml_address
+ next
->ml_size
)) {
256 memlist_free_one(dst
);
260 * don't overlap with next->ml_next
262 if ((address
+ bytes
) >
263 next
->ml_next
->ml_address
) {
264 return (MEML_SPANOP_ESPAN
);
267 * Concatenate next and next->ml_next
269 if ((address
+ bytes
) ==
270 next
->ml_next
->ml_address
) {
271 struct memlist
*mlp
= next
->ml_next
;
273 if (next
== *curmemlistp
)
274 *curmemlistp
= next
->ml_next
;
276 mlp
->ml_address
= next
->ml_address
;
277 mlp
->ml_size
+= next
->ml_size
;
278 mlp
->ml_size
+= bytes
;
281 next
->ml_prev
->ml_next
= mlp
;
282 mlp
->ml_prev
= next
->ml_prev
;
284 memlist_free_one(next
);
285 return (MEML_SPANOP_OK
);
289 next
->ml_size
+= bytes
;
291 return (MEML_SPANOP_OK
);
294 /* don't overlap with next */
295 if ((address
+ bytes
) > next
->ml_address
) {
296 memlist_free_one(dst
);
297 return (MEML_SPANOP_ESPAN
);
301 * Insert before next.
311 return (MEML_SPANOP_OK
);
315 * End of list, prev is valid and next is NULL.
321 return (MEML_SPANOP_OK
);
325 * Delete a span from a memlist.
327 * MEML_SPANOP_OK if OK.
328 * MEML_SPANOP_ESPAN if part or all of span does not exist
329 * MEML_SPANOP_EALLOC for allocation failure
335 struct memlist
**curmemlistp
)
337 struct memlist
*dst
, *next
;
340 * Find element containing address.
342 for (next
= *curmemlistp
; next
!= NULL
; next
= next
->ml_next
) {
343 if ((address
>= next
->ml_address
) &&
344 (address
< next
->ml_address
+ next
->ml_size
))
349 * If start address not in list.
352 return (MEML_SPANOP_ESPAN
);
356 * Error if size goes off end of this struct memlist.
358 if (address
+ bytes
> next
->ml_address
+ next
->ml_size
) {
359 return (MEML_SPANOP_ESPAN
);
363 * Span at beginning of struct memlist.
365 if (address
== next
->ml_address
) {
367 * If start & size match, delete from list.
369 if (bytes
== next
->ml_size
) {
370 if (next
== *curmemlistp
)
371 *curmemlistp
= next
->ml_next
;
372 if (next
->ml_prev
!= NULL
)
373 next
->ml_prev
->ml_next
= next
->ml_next
;
374 if (next
->ml_next
!= NULL
)
375 next
->ml_next
->ml_prev
= next
->ml_prev
;
377 memlist_free_one(next
);
380 * Increment start address by bytes.
382 next
->ml_address
+= bytes
;
383 next
->ml_size
-= bytes
;
385 return (MEML_SPANOP_OK
);
389 * Span at end of struct memlist.
391 if (address
+ bytes
== next
->ml_address
+ next
->ml_size
) {
393 * decrement size by bytes
395 next
->ml_size
-= bytes
;
396 return (MEML_SPANOP_OK
);
400 * Delete a span in the middle of the struct memlist.
404 * create a new struct memlist
406 dst
= memlist_get_one();
409 return (MEML_SPANOP_EALLOC
);
413 * Existing struct memlist gets address
414 * and size up to start of span.
416 dst
->ml_address
= address
+ bytes
;
418 (next
->ml_address
+ next
->ml_size
) - dst
->ml_address
;
419 next
->ml_size
= address
- next
->ml_address
;
422 * New struct memlist gets address starting
423 * after span, until end.
427 * link in new memlist after old
429 dst
->ml_next
= next
->ml_next
;
432 if (next
->ml_next
!= NULL
)
433 next
->ml_next
->ml_prev
= dst
;
436 return (MEML_SPANOP_OK
);