genode/repos/dde_linux/src/lx_kit/mapped_io_mem_range.cc
Norman Feske 4d442bca30 Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.

Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.

This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-31 13:16:07 +02:00

175 lines
4.5 KiB
C++

/*
* \brief Representation of a locally-mapped MMIO range
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/attached_dataspace.h>
#include <io_mem_session/io_mem_session.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
/* Linux emulation environment */
#include <lx_emul.h>
/* Linux emulation environment includes */
#include <lx_kit/env.h>
#include <lx_kit/internal/list.h>
#include <lx_kit/mapped_io_mem_range.h>
#include <lx_kit/pci_dev_registry.h>
#include <lx_kit/types.h>
namespace Lx_kit { class Mapped_io_mem_range; }
/**
* Representation of a locally-mapped MMIO range
*
* This class is supposed to be a private utility to support 'ioremap'.
*/
class Lx_kit::Mapped_io_mem_range : public Lx_kit::List<Mapped_io_mem_range>::Element
{
private:
Genode::size_t const _size;
Genode::addr_t const _phys;
Genode::Region_map_client _region_map;
Genode::Attached_dataspace _ds;
Genode::addr_t const _virt;
public:
Mapped_io_mem_range(Genode::Env &env,
Genode::Rm_connection &rm,
Genode::addr_t phys, Genode::size_t size,
Genode::Io_mem_dataspace_capability ds_cap,
Genode::addr_t offset)
:
_size(size),
_phys(phys),
_region_map(rm.create(size)),
_ds(env.rm(), _region_map.dataspace()),
_virt((Genode::addr_t)_ds.local_addr<void>() | (phys &0xfffUL))
{
_region_map.attach_at(ds_cap, 0, size, offset);
}
Genode::addr_t phys() const { return _phys; }
Genode::addr_t virt() const { return _virt; }
Genode::Dataspace_capability cap() const { return _ds.cap(); }
/**
* Return true if the mapped range contains the specified sub range
*/
bool phys_range(Genode::addr_t phys, Genode::size_t size) const
{
return (phys >= _phys) && (phys + size - 1 <= _phys + _size - 1);
}
/**
* Return true if the mapped range contains the specified sub range
*/
bool virt_range(Genode::addr_t virt, Genode::size_t size) const
{
return (virt >= _virt) && (virt + size - 1 <= _virt + _size - 1);
}
};
static Lx_kit::List<Lx_kit::Mapped_io_mem_range> ranges;
/************************************************
** Lx_kit::Mapped_io_mem_range implementation **
************************************************/
static Genode::Constructible<Genode::Rm_connection> _global_rm;
void *Lx::ioremap(addr_t phys_addr, unsigned long size,
Genode::Cache_attribute cache_attribute)
{
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->phys_range(phys_addr, size)) {
void * const virt = (void *)(r->virt() + phys_addr - r->phys());
log("ioremap: return sub range phys ", Hex(phys_addr), " "
"(size ", size, ") to virt ", virt);
return virt;
}
}
addr_t offset = 0;
Io_mem_dataspace_capability ds_cap =
Lx::pci_dev_registry()->io_mem(phys_addr, cache_attribute,
size, offset);
if (!ds_cap.valid()) {
error("failed to request I/O memory: ",
Hex_range<addr_t>(phys_addr, size));
return nullptr;
}
if (!_global_rm.constructed()) {
_global_rm.construct(Lx_kit::env().env());
}
Lx_kit::Mapped_io_mem_range *io_mem = nullptr;
retry<Genode::Out_of_ram>(
[&] () {
io_mem = new (&Lx_kit::env().heap())
Lx_kit::Mapped_io_mem_range(Lx_kit::env().env(), *_global_rm,
phys_addr, size, ds_cap, offset);
},
[&] () {
_global_rm->upgrade_ram(16384);
},
10
);
ranges.insert(io_mem);
log("ioremap: mapped phys ", Hex(phys_addr), " (size ", size, ") "
"to virt ", Hex(io_mem->virt()));
return (void *)io_mem->virt();
}
void Lx::iounmap(volatile void * virt)
{
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->virt() == (addr_t)virt) {
ranges.remove(r);
destroy(&Lx_kit::env().heap(), r);
return;
}
}
}
Genode::Dataspace_capability
Lx::ioremap_lookup(Genode::addr_t virt_addr, Genode::size_t size)
{
/* search for the requested region within the already mapped ranges */
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next())
if (r->virt_range(virt_addr, size))
return r->cap();
return Genode::Dataspace_capability();
}