/* * \brief Fiasco.OC-specific implementation of the IO_MEM session interface * \author Christian Helmuth * \author Stefan Kalkowski * \date 2006-08-28 */ /* * Copyright (C) 2006-2012 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. */ /* core includes */ #include #include #include /* Fiasco includes */ namespace Fiasco { #include #include } using namespace Genode; void Io_mem_session_component::_unmap_local(addr_t base, size_t size) { platform()->region_alloc()->free(reinterpret_cast(base)); } static inline bool can_use_super_page(addr_t base, size_t size) { return (base & (get_super_page_size() - 1)) == 0 && (size >= get_super_page_size()); } addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) { using namespace Fiasco; /* align large I/O dataspaces on a super-page boundary within core */ size_t alignment = (size >= get_super_page_size()) ? get_super_page_size_log2() : get_page_size_log2(); /* find appropriate region for mapping */ void *local_base = 0; if (!platform()->region_alloc()->alloc_aligned(size, &local_base, alignment)) return 0; /* call sigma0 for I/O region */ unsigned offset = 0; while (size) { /* FIXME what about caching demands? */ /* FIXME what about read / write? */ l4_utcb_mr()->mr[0] = SIGMA0_REQ_FPAGE_IOMEM; size_t page_size_log2 = get_page_size_log2(); if (can_use_super_page(base + offset, size)) page_size_log2 = get_super_page_size_log2(); l4_utcb_mr()->mr[1] = l4_fpage(base + offset, page_size_log2, L4_FPAGE_RWX).raw; /* open receive window for mapping */ l4_utcb_br()->bdr = 0; l4_utcb_br()->br[0] = L4_ITEM_MAP; l4_utcb_br()->br[1] = l4_fpage((addr_t)local_base + offset, page_size_log2, L4_FPAGE_RWX).raw; l4_msgtag_t tag = l4_msgtag(L4_PROTO_SIGMA0, 2, 0, 0); tag = l4_ipc_call(L4_BASE_PAGER_CAP, l4_utcb(), tag, L4_IPC_NEVER); if (l4_ipc_error(tag, l4_utcb())) { PERR("Ipc error %ld", l4_ipc_error(tag, l4_utcb())); return 0; } if (l4_msgtag_items(tag) < 1) { PERR("Got no mapping!"); return 0; } offset += 1 << page_size_log2; size -= 1 << page_size_log2; } return (addr_t)local_base; }