/*
* \brief Flexpage iterator
* \author Alexander Boettcher
* \date 2013-01-07
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__UTIL__FLEX_ITERATOR_H_
#define _INCLUDE__UTIL__FLEX_ITERATOR_H_
#include
#include
namespace Genode {
struct Flexpage;
class Flexpage_iterator;
}
struct Genode::Flexpage
{
addr_t addr = ~0UL;
addr_t hotspot = 0;
size_t log2_order = 0;
Flexpage() { }
Flexpage(addr_t a, addr_t h, size_t o)
: addr(a), hotspot(h), log2_order(o) { }
bool valid() { return addr != ~0UL; }
};
class Genode::Flexpage_iterator
{
private:
addr_t _src_start = 0, _src_size = 0;
addr_t _dst_start = 0, _dst_size = 0;
addr_t _hotspot = 0, _offset = 0;
/**
* Find least significant set bit in value
*/
inline addr_t
lsb_bit(addr_t const scan)
{
if (scan == 0)
return ~0UL;
return __builtin_ctzl(scan);
}
public:
Flexpage_iterator() { }
Flexpage_iterator(addr_t src_start, size_t src_size,
addr_t dst_start, size_t dst_size,
addr_t hotspot)
:
_src_start(src_start), _src_size(src_size),
_dst_start(dst_start), _dst_size(dst_size),
_hotspot(hotspot), _offset(0)
{ }
Flexpage page()
{
size_t const size = min (_src_size, _dst_size);
addr_t const from_end = _src_start + size;
addr_t const to_end = _dst_start + size;
if (_offset >= size)
return Flexpage();
addr_t const from_curr = _src_start + _offset;
addr_t const to_curr = _dst_start + _offset;
/*
* The common alignment corresponds to the number of least
* significant zero bits in both addresses.
*/
addr_t const common_bits = from_curr | to_curr;
/* find least set bit in common bits */
size_t order = lsb_bit(common_bits);
size_t max = (order == ~0UL) ? ~0UL : (1UL << order);
/* look if it still fits into both 'src' and 'dst' ranges */
if ((from_end - from_curr) < max) {
order = log2(from_end - from_curr);
order = (order == ~0UL) ? 12 : order;
max = 1UL << order;
}
if ((to_end - to_curr) < max) {
order = log2(to_end - to_curr);
order = (order == ~0UL) ? 12 : order;
}
if (order >= sizeof(_offset) * 8)
return Flexpage();
/* advance offset by current flexpage size */
_offset += (1UL << order);
return Flexpage(from_curr, _hotspot + _offset - (1UL << order), order);
}
};
#endif /* _INCLUDE__UTIL__FLEX_ITERATOR_H_ */