genode/repos/base-linux/src/include/base/internal/region_registry.h

130 lines
2.6 KiB
C++

/*
* \brief Registry of virtual-memory regions
* \author Norman Feske
* \date 2016-04-29
*/
/*
* Copyright (C) 2016-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__BASE__INTERNAL__REGION_REGISTRY_
#define _INCLUDE__BASE__INTERNAL__REGION_REGISTRY_
#include <dataspace/capability.h>
#include <base/log.h>
namespace Genode {
class Region;
class Region_registry;
}
class Genode::Region
{
private:
addr_t _start { 0 };
off_t _offset { 0 };
Dataspace_capability _ds { };
size_t _size { 0 };
/**
* Return offset of first byte after the region
*/
addr_t _end() const { return _start + _size; }
public:
Region() { }
Region(addr_t start, off_t offset, Dataspace_capability ds, size_t size)
: _start(start), _offset(offset), _ds(ds), _size(size) { }
bool used() const { return _size > 0; }
addr_t start() const { return _start; }
off_t offset() const { return _offset; }
size_t size() const { return _size; }
Dataspace_capability dataspace() const { return _ds; }
bool intersects(Region const &r) const
{
return (r.start() < _end()) && (_start < r._end());
}
};
class Genode::Region_registry
{
public:
enum { MAX_REGIONS = 4096 };
private:
Region _map[MAX_REGIONS];
bool _id_valid(int id) const {
return (id >= 0 && id < MAX_REGIONS); }
public:
/**
* Add region to region map
*
* \return region ID, or
* -1 if out of metadata, or
* -2 if region conflicts existing region
*/
int add_region(Region const &region)
{
/*
* Check for region conflicts
*/
for (int i = 0; i < MAX_REGIONS; i++) {
if (_map[i].intersects(region))
return -2;
}
/*
* Allocate new region metadata
*/
int i;
for (i = 0; i < MAX_REGIONS; i++)
if (!_map[i].used()) break;
if (i == MAX_REGIONS) {
error("maximum number of ", (unsigned)MAX_REGIONS, " regions reached");
return -1;
}
_map[i] = region;
return i;
}
Region region(int id) const
{
return _id_valid(id) ? _map[id] : Region();
}
Region lookup(addr_t start)
{
for (int i = 0; i < MAX_REGIONS; i++)
if (_map[i].start() == start)
return _map[i];
return Region();
}
void remove_region(addr_t start)
{
for (int i = 0; i < MAX_REGIONS; i++)
if (_map[i].start() == start)
_map[i] = Region();
}
};
#endif /* _INCLUDE__BASE__INTERNAL__REGION_REGISTRY_ */