/* * \brief Core implementation of the IO_MEM session interface * \author Christian Helmuth * \date 2006-08-01 */ /* * Copyright (C) 2006-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #include #include #include #include #include #include #include "util.h" using namespace Genode; static const bool verbose = false; Io_mem_session_component::Dataspace_attr Io_mem_session_component::_prepare_io_mem(const char *args, Range_allocator *ram_alloc) { addr_t req_base = Arg_string::find_arg(args, "base").ulong_value(0); size_t req_size = Arg_string::find_arg(args, "size").ulong_value(0); /* align base and size on page boundaries */ addr_t end = align_addr(req_base + req_size, get_page_size_log2()); addr_t base = req_base & ~(get_page_size() - 1); size_t size = end - base; _write_combined = false; Arg a = Arg_string::find_arg(args, "wc"); if (a.valid()) _write_combined = a.bool_value(0); /* check for RAM collision */ int ret; if ((ret = ram_alloc->remove_range(base, size))) { PERR("I/O memory [%lx,%lx) used by RAM allocator (%d)", base, base + size, ret); return Dataspace_attr(); } /* allocate region */ switch (_io_mem_alloc->alloc_addr(req_size, req_base).value) { case Range_allocator::Alloc_return::RANGE_CONFLICT: PERR("I/O memory [%lx,%lx) not available", req_base, req_base + req_size); return Dataspace_attr(); case Range_allocator::Alloc_return::OUT_OF_METADATA: PERR("I/O memory allocator ran out of meta data"); return Dataspace_attr(); case Range_allocator::Alloc_return::OK: break; } /* request local mapping */ addr_t local_addr = _map_local(base, size); if (verbose) PDBG("I/O mem [%lx,%lx) => [%lx,%lx)%s", base, base + size, local_addr, local_addr + size, _write_combined ? " (write-combined)" : ""); return Dataspace_attr(size, local_addr, base, _write_combined, req_base); } Io_mem_session_component::Io_mem_session_component(Range_allocator *io_mem_alloc, Range_allocator *ram_alloc, Rpc_entrypoint *ds_ep, const char *args) : _io_mem_alloc(io_mem_alloc), _ds(_prepare_io_mem(args, ram_alloc)), _ds_ep(ds_ep) { if (!_ds.valid()) { PERR("Local MMIO mapping failed!"); _ds_cap = Io_mem_dataspace_capability(); throw Root::Invalid_args(); } _ds_cap = static_cap_cast(_ds_ep->manage(&_ds)); } Io_mem_session_component::~Io_mem_session_component() { if (verbose) PDBG("I/O mem free [%lx,%lx)", _ds.phys_addr(), _ds.phys_addr() + _ds.size()); /* dissolve IO_MEM dataspace from service entry point */ _ds_ep->dissolve(&_ds); /* flush local mapping of IO_MEM */ _unmap_local(_ds.core_local_addr(), _ds.size()); /* * The Dataspace will remove itself from all RM sessions when its * destructor is called. Thereby, it will get unmapped from all RM * clients that currently have the dataspace attached. */ /* free region in IO_MEM allocator */ _io_mem_alloc->free(reinterpret_cast(_ds.req_base)); }