/* * \brief L4Re functions needed by L4Linux. * \author Stefan Kalkowski * \date 2011-04-17 */ /* * Copyright (C) 2011-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. */ /* Genode includes */ #include #include #include #include #include namespace Fiasco { #include #include #include } using namespace Fiasco; static const bool DEBUG = false; /* print usage of region map functions */ static const bool DEBUG_FIND = false; /* print also usage of region map lookups */ static const bool DEBUG_SEARCH = false; /* print also information about the search for alternative address ranges */ enum { L4RE_SEARCH_FOR_REGION = 0x20, L4RE_REGION_RESERVED = 0x08 }; extern "C" { int l4re_rm_find(l4_addr_t *addr, unsigned long *size, l4_addr_t *offset, unsigned *flags, l4re_ds_t *m) { using namespace L4lx; if(DEBUG_FIND) PDBG("addr=%lx size=%lx", *addr, *size); *m = L4_INVALID_CAP; Region *r = Env::env()->rm()->find_region(addr, (Genode::size_t*)size); if (r) { if (r->ds()) *m = r->ds()->ref(); *flags = L4RE_REGION_RESERVED; } else *flags = 0; if(DEBUG_FIND) PDBG("Found addr=%lx size=%lx reserved?=%x ds=%lx", *addr, *size, *flags, *m); return 0; } int l4re_rm_attach(void **start, unsigned long size, unsigned long flags, l4re_ds_t const mem, l4_addr_t offs, unsigned char align) { using namespace Genode; void *original_start = *start; if (DEBUG) PDBG("start=%p size=%lx flags=%lx mem=%lx offs=%lx align=%u", *start, size, flags, mem, offs, align); L4lx::Dataspace *ds = L4lx::Env::env()->dataspaces()->find_by_ref(mem); if (!ds) { PERR("mem=%lx doesn't exist", mem); return -L4_ERANGE; } while (!L4lx::Env::env()->rm()->attach_at(ds, size, offs, *start)) { if (flags & L4RE_SEARCH_FOR_REGION) /* search flag */ { /* the original start address might have a different alignment */ l4_addr_t start_addr = (l4_addr_t)*start; l4_addr_t aligned_start_addr = align_addr(start_addr, align); if (aligned_start_addr != start_addr) { if (DEBUG_SEARCH) PDBG("attach failed: start=%lx, trying %lx instead", start_addr, aligned_start_addr); *start = (void*)aligned_start_addr; } else { if (start_addr <= ((addr_t)~0 - 2*(1 << align) + 1)) { if (DEBUG_SEARCH) PDBG("attach failed: start=%lx, trying %lx instead", start_addr, start_addr + (1 << align)); start_addr += (1 << align); *start = (void*)start_addr; } else { PWRN("Couldn't attach ds of size 0x%lx at %p", size, original_start); return -L4_ERANGE; } } } else { PWRN("Couldn't attach ds of size 0x%lx at %p", size, original_start); return -L4_ERANGE; } } if (DEBUG) PDBG("attached at %p", *start); return 0; } int l4re_rm_detach(void *addr) { if(DEBUG) PDBG("addr=%p", addr); Genode::addr_t start = (Genode::addr_t) addr; Genode::size_t size = 0; L4lx::Region *r = L4lx::Env::env()->rm()->find_region(&start, &size); if (!r) { PWRN("Nothing found at %p", addr); return -1; } Genode::env()->rm_session()->detach(addr); L4lx::Env::env()->rm()->free((void*)start); return 0; } int l4re_rm_reserve_area(l4_addr_t *start, unsigned long size, unsigned flags, unsigned char align) { if (DEBUG) PDBG("*start=%lx size=%lx align=%u flags=%x", *start, size, align, flags); L4lx::Region *r = L4lx::Env::env()->rm()->reserve_range(size, align, *start); if (r) { *start = (l4_addr_t) r->addr(); if (DEBUG) PDBG("return %lx", *start); return 0; } PWRN("Could not reserve area!"); return -1; } int l4re_rm_free_area(l4_addr_t addr) { L4lx::Region* md = L4lx::Env::env()->rm()->metadata((void*)addr); if (DEBUG) PDBG("%lx", addr); if (!md) { PWRN("No region found at %p", (void*) addr); return -1; } /* gets freed only if there is no dataspace attached */ if (!md->ds()->cap().valid()) L4lx::Env::env()->rm()->free((void*)addr); return 0; } void l4re_rm_show_lists(void) { L4lx::Env::env()->rm()->dump(); } }