mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
base-linux: remove exceptions from region_map_mmap
This patch replaces the exception-based error propagation by the use of 'Attempt' return values, which eliminates side effects of the exception handling - cxx_heap allocations - from code paths that are used by the the cxx_heap itself (when growing the cxx_heap). It thereby fixes the failure of the sub_rm test at the "attach RAM ds to any position at sub rm - this should fail" step. Fixes #4953
This commit is contained in:
parent
75bfc37b18
commit
852bc3fc62
@ -60,26 +60,35 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace
|
||||
|
||||
bool _is_attached() const { return _base > 0; }
|
||||
|
||||
void _add_to_rmap(Region const &);
|
||||
/*
|
||||
* \return true on success
|
||||
*/
|
||||
bool _add_to_rmap(Region const &);
|
||||
|
||||
enum class Reserve_local_error { REGION_CONFLICT };
|
||||
using Reserve_local_result = Attempt<addr_t, Reserve_local_error>;
|
||||
|
||||
/**
|
||||
* Reserve VM region for sub-rm dataspace
|
||||
*/
|
||||
addr_t _reserve_local(bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
size_t size);
|
||||
Reserve_local_result _reserve_local(bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
size_t size);
|
||||
|
||||
enum class Map_local_error { REGION_CONFLICT };
|
||||
using Map_local_result = Attempt<void *, Map_local_error>;
|
||||
|
||||
/**
|
||||
* Map dataspace into local address space
|
||||
*/
|
||||
void *_map_local(Dataspace_capability ds,
|
||||
size_t size,
|
||||
addr_t offset,
|
||||
bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
bool executable,
|
||||
bool overmap,
|
||||
bool writeable);
|
||||
Map_local_result _map_local(Dataspace_capability ds,
|
||||
size_t size,
|
||||
addr_t offset,
|
||||
bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
bool executable,
|
||||
bool overmap,
|
||||
bool writeable);
|
||||
|
||||
/**
|
||||
* Determine size of dataspace
|
||||
@ -117,8 +126,48 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace
|
||||
** Region map interface **
|
||||
**************************/
|
||||
|
||||
Local_addr attach(Dataspace_capability, size_t size, off_t, bool,
|
||||
Local_addr, bool, bool) override;
|
||||
struct Attach_attr
|
||||
{
|
||||
size_t size;
|
||||
off_t offset;
|
||||
bool use_local_addr;
|
||||
void *local_addr;
|
||||
bool executable;
|
||||
bool writeable;
|
||||
};
|
||||
|
||||
enum class Attach_error
|
||||
{
|
||||
INVALID_DATASPACE, REGION_CONFLICT, OUT_OF_RAM, OUT_OF_CAPS
|
||||
};
|
||||
|
||||
using Attach_result = Attempt<Local_addr, Attach_error>;
|
||||
|
||||
Attach_result attach(Dataspace_capability, Attach_attr const &);
|
||||
|
||||
Local_addr attach(Dataspace_capability ds, size_t size, off_t offset,
|
||||
bool use_local_addr, Local_addr local_addr,
|
||||
bool executable, bool writeable) override
|
||||
{
|
||||
Attach_attr const attr { .size = size,
|
||||
.offset = offset,
|
||||
.use_local_addr = use_local_addr,
|
||||
.local_addr = local_addr,
|
||||
.executable = executable,
|
||||
.writeable = writeable };
|
||||
|
||||
return attach(ds, attr).convert<Local_addr>(
|
||||
[&] (Local_addr local_addr) { return local_addr; },
|
||||
[&] (Attach_error e) -> Local_addr {
|
||||
switch (e) {
|
||||
case Attach_error::INVALID_DATASPACE: throw Invalid_dataspace();
|
||||
case Attach_error::REGION_CONFLICT: throw Region_conflict();
|
||||
case Attach_error::OUT_OF_RAM: throw Out_of_ram();
|
||||
case Attach_error::OUT_OF_CAPS: throw Out_of_caps();
|
||||
}
|
||||
throw Region_conflict();
|
||||
});
|
||||
}
|
||||
|
||||
void detach(Local_addr) override;
|
||||
|
||||
|
@ -73,9 +73,8 @@ static Mutex &mutex()
|
||||
}
|
||||
|
||||
|
||||
addr_t Region_map_mmap::_reserve_local(bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
Genode::size_t size)
|
||||
Region_map_mmap::Reserve_local_result
|
||||
Region_map_mmap::_reserve_local(bool use_local_addr, addr_t local_addr, size_t size)
|
||||
{
|
||||
/* special handling for stack area */
|
||||
if (use_local_addr
|
||||
@ -113,21 +112,22 @@ addr_t Region_map_mmap::_reserve_local(bool use_local_addr,
|
||||
|| (((long)addr_out < 0) && ((long)addr_out > -4095))) {
|
||||
error("_reserve_local: lx_mmap failed "
|
||||
"(addr_in=", addr_in, ",addr_out=", addr_out, "/", (long)addr_out, ")");
|
||||
throw Region_map::Region_conflict();
|
||||
return Reserve_local_error::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
return (addr_t) addr_out;
|
||||
}
|
||||
|
||||
|
||||
void *Region_map_mmap::_map_local(Dataspace_capability ds,
|
||||
Genode::size_t size,
|
||||
addr_t offset,
|
||||
bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
bool executable,
|
||||
bool overmap,
|
||||
bool writeable)
|
||||
Region_map_mmap::Map_local_result
|
||||
Region_map_mmap::_map_local(Dataspace_capability ds,
|
||||
size_t size,
|
||||
addr_t offset,
|
||||
bool use_local_addr,
|
||||
addr_t local_addr,
|
||||
bool executable,
|
||||
bool overmap,
|
||||
bool writeable)
|
||||
{
|
||||
writeable = _dataspace_writeable(ds) && writeable;
|
||||
|
||||
@ -156,19 +156,20 @@ void *Region_map_mmap::_map_local(Dataspace_capability ds,
|
||||
error("_map_local: lx_mmap failed"
|
||||
"(addr_in=", addr_in, ", addr_out=", addr_out, "/", (long)addr_out, ") "
|
||||
"overmap=", overmap);
|
||||
throw Region_map::Region_conflict();
|
||||
return Map_local_error::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
|
||||
void Region_map_mmap::_add_to_rmap(Region const ®ion)
|
||||
bool Region_map_mmap::_add_to_rmap(Region const ®ion)
|
||||
{
|
||||
if (_rmap.add_region(region) < 0) {
|
||||
error("_add_to_rmap: could not add region to sub RM session");
|
||||
throw Region_conflict();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -190,38 +191,35 @@ struct Inhibit_tracing_guard
|
||||
};
|
||||
|
||||
|
||||
Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
size_t size, off_t offset,
|
||||
bool use_local_addr,
|
||||
Region_map::Local_addr local_addr,
|
||||
bool executable, bool writeable)
|
||||
Region_map_mmap::Attach_result
|
||||
Region_map_mmap::attach(Dataspace_capability ds, Attach_attr const &attr)
|
||||
{
|
||||
Mutex::Guard mutex_guard(mutex());
|
||||
|
||||
Inhibit_tracing_guard it_guard { };
|
||||
|
||||
/* only support attach_at for sub RM sessions */
|
||||
if (_sub_rm && !use_local_addr) {
|
||||
if (_sub_rm && !attr.use_local_addr) {
|
||||
error("Region_map_mmap::attach: attaching w/o local addr not supported");
|
||||
throw Region_conflict();
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
if (attr.offset < 0) {
|
||||
error("Region_map_mmap::attach: negative offset not supported");
|
||||
throw Region_conflict();
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
if (!ds.valid())
|
||||
throw Invalid_dataspace();
|
||||
return Attach_error::INVALID_DATASPACE;
|
||||
|
||||
size_t const remaining_ds_size = _dataspace_size(ds) > (addr_t)offset
|
||||
? _dataspace_size(ds) - (addr_t)offset : 0;
|
||||
size_t const remaining_ds_size = _dataspace_size(ds) > (addr_t)attr.offset
|
||||
? _dataspace_size(ds) - (addr_t)attr.offset : 0;
|
||||
|
||||
/* determine size of virtual address region */
|
||||
size_t const region_size = size ? min(remaining_ds_size, size)
|
||||
: remaining_ds_size;
|
||||
size_t const region_size = attr.size ? min(remaining_ds_size, attr.size)
|
||||
: remaining_ds_size;
|
||||
if (region_size == 0)
|
||||
throw Region_conflict();
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
|
||||
/*
|
||||
* We have to distinguish the following cases
|
||||
@ -243,19 +241,20 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
*/
|
||||
if (is_sub_rm_session(ds)) {
|
||||
error("Region_map_mmap::attach: nesting sub RM sessions is not supported");
|
||||
throw Invalid_dataspace();
|
||||
return Attach_error::INVALID_DATASPACE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for the dataspace to not exceed the boundaries of the
|
||||
* sub RM session
|
||||
*/
|
||||
if (region_size + (addr_t)local_addr > _size) {
|
||||
if (region_size + (addr_t)attr.local_addr > _size) {
|
||||
error("Region_map_mmap::attach: dataspace does not fit in sub RM session");
|
||||
throw Region_conflict();
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
_add_to_rmap(Region(local_addr, offset, ds, region_size));
|
||||
if (!_add_to_rmap(Region((addr_t)attr.local_addr, attr.offset, ds, region_size)))
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
|
||||
/*
|
||||
* Case 3.1
|
||||
@ -266,9 +265,11 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
* argument as the region was reserved by a PROT_NONE mapping.
|
||||
*/
|
||||
if (_is_attached())
|
||||
_map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true, writeable);
|
||||
_map_local(ds, region_size, attr.offset,
|
||||
true, _base + (addr_t)attr.local_addr,
|
||||
attr.executable, true, attr.writeable);
|
||||
|
||||
return (void *)local_addr;
|
||||
return Local_addr(attr.local_addr);
|
||||
|
||||
} else {
|
||||
|
||||
@ -279,7 +280,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
Region_map_mmap *rm = dynamic_cast<Region_map_mmap *>(ds_if);
|
||||
|
||||
if (!rm)
|
||||
throw Invalid_dataspace();
|
||||
return Attach_error::INVALID_DATASPACE;
|
||||
|
||||
/*
|
||||
* Case 2.1
|
||||
@ -288,39 +289,52 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
*/
|
||||
if (rm->_base) {
|
||||
error("Region_map_mmap::attach: mapping a sub RM session twice is not supported");
|
||||
throw Region_conflict();
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve local address range that can hold the entire sub RM
|
||||
* session.
|
||||
*/
|
||||
rm->_base = _reserve_local(use_local_addr, local_addr, region_size);
|
||||
return _reserve_local(attr.use_local_addr, (addr_t)attr.local_addr,
|
||||
region_size)
|
||||
.convert<Attach_result>(
|
||||
|
||||
_add_to_rmap(Region(rm->_base, offset, ds, region_size));
|
||||
[&] (addr_t base) -> Attach_result
|
||||
{
|
||||
rm->_base = base;
|
||||
|
||||
/*
|
||||
* Cases 2.2, 3.2
|
||||
*
|
||||
* The sub rm session was not attached until now but it may have
|
||||
* been populated with dataspaces. Go through all regions and map
|
||||
* each of them.
|
||||
*/
|
||||
for (int i = 0; i < Region_registry::MAX_REGIONS; i++) {
|
||||
Region region = rm->_rmap.region(i);
|
||||
if (!region.used())
|
||||
continue;
|
||||
if (!_add_to_rmap(Region(rm->_base, attr.offset, ds, region_size)))
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
|
||||
/*
|
||||
* We have to enforce the mapping via the 'overmap' argument as
|
||||
* the region was reserved by a PROT_NONE mapping.
|
||||
*/
|
||||
_map_local(region.dataspace(), region.size(), region.offset(),
|
||||
true, rm->_base + region.start() + region.offset(),
|
||||
executable, true, writeable);
|
||||
}
|
||||
/*
|
||||
* Cases 2.2, 3.2
|
||||
*
|
||||
* The sub rm session was not attached until now but it may have
|
||||
* been populated with dataspaces. Go through all regions and map
|
||||
* each of them.
|
||||
*/
|
||||
for (int i = 0; i < Region_registry::MAX_REGIONS; i++) {
|
||||
Region region = rm->_rmap.region(i);
|
||||
if (!region.used())
|
||||
continue;
|
||||
|
||||
return rm->_base;
|
||||
/*
|
||||
* We have to enforce the mapping via the 'overmap' argument as
|
||||
* the region was reserved by a PROT_NONE mapping.
|
||||
*/
|
||||
_map_local(region.dataspace(), region.size(), region.offset(),
|
||||
true, rm->_base + region.start() + region.offset(),
|
||||
attr.executable, true, attr.writeable);
|
||||
}
|
||||
|
||||
return Local_addr(rm->_base);
|
||||
},
|
||||
[&] (Reserve_local_error e) {
|
||||
switch (e) { case Reserve_local_error::REGION_CONFLICT: break; }
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
}
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
@ -330,12 +344,23 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
* Boring, a plain dataspace is attached to a root RM session.
|
||||
* Note, we do not overmap.
|
||||
*/
|
||||
void *addr = _map_local(ds, region_size, offset, use_local_addr,
|
||||
local_addr, executable, false, writeable);
|
||||
return _map_local(ds, region_size, attr.offset, attr.use_local_addr,
|
||||
(addr_t)attr.local_addr, attr.executable, false,
|
||||
attr.writeable)
|
||||
.convert<Attach_result>(
|
||||
|
||||
_add_to_rmap(Region((addr_t)addr, offset, ds, region_size));
|
||||
[&] (void *addr) -> Attach_result {
|
||||
if (_add_to_rmap(Region((addr_t)addr, attr.offset, ds, region_size)))
|
||||
return Local_addr(addr);
|
||||
|
||||
return addr;
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
},
|
||||
|
||||
[&] (Map_local_error e) {
|
||||
switch (e) { case Map_local_error::REGION_CONFLICT: break; }
|
||||
return Attach_error::REGION_CONFLICT;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user