1// vi:set ft=cpp: -*- Mode: C++ -*-
2
3#pragma once
4
5#include <l4/sys/consts.h>
6
7namespace L4 {
8
9  /**
10   * Round a value down so the given number of lsb is zero.
11   *
12   * \tparam T     The type of the value (shall be some integral type.
13   * \param val    The value where the given lsb shall be masked.
14   * \param order  the number of least significant bits (lsb) to mask.
15   * \return val with order lsb masked to zero.
16   */
17  template<typename T>
18  constexpr T trunc_order(T val, unsigned char order)
19  {
20    return val & ((~T(0)) << order);
21  }
22
23  /**
24   * Round a value up so the given number of lsb is zero.
25   *
26   * \tparam T     The type of the value (shall be some integral type.
27   * \param val    The value to rund up to the next multiple of 2^order.
28   * \param order  order (2^order) to round up to.
29   * \return val rounded up to the next 2^order.
30   */
31  template<typename T>
32  constexpr T round_order(T val, unsigned char order)
33  {
34    return (val + (T(1) << order) - T(1)) & ((~T(0)) << order);
35  }
36
37  template<typename T>
38  constexpr T trunc_page(T val)
39  {
40    return trunc_order(val, L4_PAGESHIFT);
41  }
42
43  template<typename T>
44  constexpr T round_page(T val)
45  {
46    return round_order(val, L4_PAGESHIFT);
47  }
48
49  template<typename T>
50  inline unsigned char
51  max_order(unsigned char order, T addr,
52           T min_addr, T max_addr,
53           T hotspot = T(0))
54  {
55    while (order < 30 /* limit to 1GB flexpages */)
56      {
57        T mask;
58        T base = trunc_order(addr, order + 1);
59        if (base < min_addr)
60          return order;
61
62        if (base + (T(1) << (order + 1)) - T(1) > max_addr - T(1))
63          return order;
64
65        mask = ~((~T(0)) << (order + 1));
66        if (hotspot == ~T(0) || ((addr ^ hotspot) & mask))
67          break;
68
69        ++order;
70      }
71
72    return order;
73  }
74
75}
76