1 /**
2  * \file
3  * \brief Split a range in log2 aligned and size-aligned chunks.
4  */
5 /*
6  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
7  *     economic rights: Technische Universität Dresden (Germany)
8  * This file is part of TUD:OS and distributed under the terms of the
9  * GNU Lesser General Public License 2.1.
10  * Please see the COPYING-LGPL-2.1 file for details.
11  */
12 #ifndef __L4UTIL__INCLUDE__SPLITLOG2_H__
13 #define __L4UTIL__INCLUDE__SPLITLOG2_H__
14 
15 #include <l4/sys/linkage.h>
16 #include <l4/sys/err.h>
17 #include <l4/util/bitops.h>
18 
19 EXTERN_C_BEGIN
20 
21 /**
22  * \brief Split a range into log2 base and size aligned chunks.
23  * \ingroup l4util_api
24  *
25  * \param start   Start of range
26  * \param end     End of range (inclusive) (e.g. 2-4 is len 3)
27  * \param handler Handler function that is called with start and end
28  *                (both inclusive) of the chunk. On success, the handler
29  *                must return 0, if it returns !=0 the function will
30  *                immediately return with the return code of the handler.
31  * \return 0 on success, != 0 otherwise
32  */
33 L4_INLINE long
34 l4util_splitlog2_hdl(l4_addr_t start, l4_addr_t end,
35                      long (*handler)(l4_addr_t s, l4_addr_t e, int log2size));
36 
37 /**
38  * \brief Return log2 base and size aligned length of a range.
39  * \ingroup l4util_api
40  *
41  * \param start   Start of range
42  * \param end     End of range (inclusive) (e.g. 2-4 is len 3)
43  * \return length of elements in log2size (length is 1 << log2size)
44  */
45 L4_INLINE l4_addr_t
46 l4util_splitlog2_size(l4_addr_t start, l4_addr_t end);
47 
48 EXTERN_C_END
49 
50 /* Implementation */
51 
52 L4_INLINE long
l4util_splitlog2_hdl(l4_addr_t start,l4_addr_t end,long (* handler)(l4_addr_t s,l4_addr_t e,int log2size))53 l4util_splitlog2_hdl(l4_addr_t start, l4_addr_t end,
54                      long (*handler)(l4_addr_t s, l4_addr_t e, int log2size))
55 {
56   if (end < start)
57     return -L4_EINVAL;
58 
59   while (start <= end)
60     {
61       long retval;
62       int len2 = l4util_splitlog2_size(start, end);
63       l4_addr_t len = 1UL << len2;
64       if ((retval = handler(start, start + len - 1, len2)))
65 	return retval;
66       start += len;
67     }
68   return 0;
69 }
70 
71 L4_INLINE l4_addr_t
l4util_splitlog2_size(l4_addr_t start,l4_addr_t end)72 l4util_splitlog2_size(l4_addr_t start, l4_addr_t end)
73 {
74   int start_bits = l4util_bsf(start);
75   int len_bits = l4util_bsr(end - start + 1);
76   if (start_bits != -1 && len_bits > start_bits)
77     len_bits = start_bits;
78 
79   return len_bits;
80 }
81 
82 #endif /* ! __L4UTIL__INCLUDE__SPLITLOG2_H__ */
83