mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-07 11:08:41 +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; }
|
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
|
* Reserve VM region for sub-rm dataspace
|
||||||
*/
|
*/
|
||||||
addr_t _reserve_local(bool use_local_addr,
|
Reserve_local_result _reserve_local(bool use_local_addr,
|
||||||
addr_t local_addr,
|
addr_t local_addr,
|
||||||
size_t size);
|
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
|
* Map dataspace into local address space
|
||||||
*/
|
*/
|
||||||
void *_map_local(Dataspace_capability ds,
|
Map_local_result _map_local(Dataspace_capability ds,
|
||||||
size_t size,
|
size_t size,
|
||||||
addr_t offset,
|
addr_t offset,
|
||||||
bool use_local_addr,
|
bool use_local_addr,
|
||||||
addr_t local_addr,
|
addr_t local_addr,
|
||||||
bool executable,
|
bool executable,
|
||||||
bool overmap,
|
bool overmap,
|
||||||
bool writeable);
|
bool writeable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine size of dataspace
|
* Determine size of dataspace
|
||||||
@ -117,8 +126,48 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace
|
|||||||
** Region map interface **
|
** Region map interface **
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
Local_addr attach(Dataspace_capability, size_t size, off_t, bool,
|
struct Attach_attr
|
||||||
Local_addr, bool, bool) override;
|
{
|
||||||
|
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;
|
void detach(Local_addr) override;
|
||||||
|
|
||||||
|
@ -73,9 +73,8 @@ static Mutex &mutex()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
addr_t Region_map_mmap::_reserve_local(bool use_local_addr,
|
Region_map_mmap::Reserve_local_result
|
||||||
addr_t local_addr,
|
Region_map_mmap::_reserve_local(bool use_local_addr, addr_t local_addr, size_t size)
|
||||||
Genode::size_t size)
|
|
||||||
{
|
{
|
||||||
/* special handling for stack area */
|
/* special handling for stack area */
|
||||||
if (use_local_addr
|
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))) {
|
|| (((long)addr_out < 0) && ((long)addr_out > -4095))) {
|
||||||
error("_reserve_local: lx_mmap failed "
|
error("_reserve_local: lx_mmap failed "
|
||||||
"(addr_in=", addr_in, ",addr_out=", addr_out, "/", (long)addr_out, ")");
|
"(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;
|
return (addr_t) addr_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *Region_map_mmap::_map_local(Dataspace_capability ds,
|
Region_map_mmap::Map_local_result
|
||||||
Genode::size_t size,
|
Region_map_mmap::_map_local(Dataspace_capability ds,
|
||||||
addr_t offset,
|
size_t size,
|
||||||
bool use_local_addr,
|
addr_t offset,
|
||||||
addr_t local_addr,
|
bool use_local_addr,
|
||||||
bool executable,
|
addr_t local_addr,
|
||||||
bool overmap,
|
bool executable,
|
||||||
bool writeable)
|
bool overmap,
|
||||||
|
bool writeable)
|
||||||
{
|
{
|
||||||
writeable = _dataspace_writeable(ds) && 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"
|
error("_map_local: lx_mmap failed"
|
||||||
"(addr_in=", addr_in, ", addr_out=", addr_out, "/", (long)addr_out, ") "
|
"(addr_in=", addr_in, ", addr_out=", addr_out, "/", (long)addr_out, ") "
|
||||||
"overmap=", overmap);
|
"overmap=", overmap);
|
||||||
throw Region_map::Region_conflict();
|
return Map_local_error::REGION_CONFLICT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr_out;
|
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) {
|
if (_rmap.add_region(region) < 0) {
|
||||||
error("_add_to_rmap: could not add region to sub RM session");
|
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,
|
Region_map_mmap::Attach_result
|
||||||
size_t size, off_t offset,
|
Region_map_mmap::attach(Dataspace_capability ds, Attach_attr const &attr)
|
||||||
bool use_local_addr,
|
|
||||||
Region_map::Local_addr local_addr,
|
|
||||||
bool executable, bool writeable)
|
|
||||||
{
|
{
|
||||||
Mutex::Guard mutex_guard(mutex());
|
Mutex::Guard mutex_guard(mutex());
|
||||||
|
|
||||||
Inhibit_tracing_guard it_guard { };
|
Inhibit_tracing_guard it_guard { };
|
||||||
|
|
||||||
/* only support attach_at for sub RM sessions */
|
/* 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");
|
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");
|
error("Region_map_mmap::attach: negative offset not supported");
|
||||||
throw Region_conflict();
|
return Attach_error::REGION_CONFLICT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ds.valid())
|
if (!ds.valid())
|
||||||
throw Invalid_dataspace();
|
return Attach_error::INVALID_DATASPACE;
|
||||||
|
|
||||||
size_t const remaining_ds_size = _dataspace_size(ds) > (addr_t)offset
|
size_t const remaining_ds_size = _dataspace_size(ds) > (addr_t)attr.offset
|
||||||
? _dataspace_size(ds) - (addr_t)offset : 0;
|
? _dataspace_size(ds) - (addr_t)attr.offset : 0;
|
||||||
|
|
||||||
/* determine size of virtual address region */
|
/* determine size of virtual address region */
|
||||||
size_t const region_size = size ? min(remaining_ds_size, size)
|
size_t const region_size = attr.size ? min(remaining_ds_size, attr.size)
|
||||||
: remaining_ds_size;
|
: remaining_ds_size;
|
||||||
if (region_size == 0)
|
if (region_size == 0)
|
||||||
throw Region_conflict();
|
return Attach_error::REGION_CONFLICT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to distinguish the following cases
|
* 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)) {
|
if (is_sub_rm_session(ds)) {
|
||||||
error("Region_map_mmap::attach: nesting sub RM sessions is not supported");
|
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
|
* Check for the dataspace to not exceed the boundaries of the
|
||||||
* sub RM session
|
* 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");
|
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
|
* 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.
|
* argument as the region was reserved by a PROT_NONE mapping.
|
||||||
*/
|
*/
|
||||||
if (_is_attached())
|
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 {
|
} 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);
|
Region_map_mmap *rm = dynamic_cast<Region_map_mmap *>(ds_if);
|
||||||
|
|
||||||
if (!rm)
|
if (!rm)
|
||||||
throw Invalid_dataspace();
|
return Attach_error::INVALID_DATASPACE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Case 2.1
|
* Case 2.1
|
||||||
@ -288,39 +289,52 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
|||||||
*/
|
*/
|
||||||
if (rm->_base) {
|
if (rm->_base) {
|
||||||
error("Region_map_mmap::attach: mapping a sub RM session twice is not supported");
|
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
|
* Reserve local address range that can hold the entire sub RM
|
||||||
* session.
|
* 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;
|
||||||
|
|
||||||
/*
|
if (!_add_to_rmap(Region(rm->_base, attr.offset, ds, region_size)))
|
||||||
* Cases 2.2, 3.2
|
return Attach_error::REGION_CONFLICT;
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to enforce the mapping via the 'overmap' argument as
|
* Cases 2.2, 3.2
|
||||||
* the region was reserved by a PROT_NONE mapping.
|
*
|
||||||
*/
|
* The sub rm session was not attached until now but it may have
|
||||||
_map_local(region.dataspace(), region.size(), region.offset(),
|
* been populated with dataspaces. Go through all regions and map
|
||||||
true, rm->_base + region.start() + region.offset(),
|
* each of them.
|
||||||
executable, true, writeable);
|
*/
|
||||||
}
|
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 {
|
} 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.
|
* Boring, a plain dataspace is attached to a root RM session.
|
||||||
* Note, we do not overmap.
|
* Note, we do not overmap.
|
||||||
*/
|
*/
|
||||||
void *addr = _map_local(ds, region_size, offset, use_local_addr,
|
return _map_local(ds, region_size, attr.offset, attr.use_local_addr,
|
||||||
local_addr, executable, false, writeable);
|
(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…
x
Reference in New Issue
Block a user