diff --git a/base-fiasco/src/core/include/map_local.h b/base-fiasco/src/core/include/map_local.h index 0fa764736..940de1c76 100644 --- a/base-fiasco/src/core/include/map_local.h +++ b/base-fiasco/src/core/include/map_local.h @@ -70,6 +70,17 @@ namespace Genode { } return true; } + + /** + * Unmap pages locally within core + * + * \param virt core-local address + * \param num_pages number of pages to unmap + */ + inline void unmap_local(addr_t virt, size_t num_pages) + { + PERR("unmap_local() called - not implemented yet"); + } } #endif /* _CORE__INCLUDE__MAP_LOCAL_H_ */ diff --git a/base-nova/src/core/include/map_local.h b/base-nova/src/core/include/map_local.h index c1d37746c..3af9cb85e 100644 --- a/base-nova/src/core/include/map_local.h +++ b/base-nova/src/core/include/map_local.h @@ -30,15 +30,27 @@ namespace Genode { * the physical address space. * * \param from_phys physical source address - * \param to_addr core-local destination address + * \param to_virt core-local destination address * \param num_pages number of pages to map * * \return true on success */ inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages) { - return ::map_local((Nova::Utcb *)Thread_base::myself()->utcb(), - from_phys, to_virt, num_pages, true); + return (::map_local((Nova::Utcb *)Thread_base::myself()->utcb(), + from_phys, to_virt, num_pages, true) == 0); + } + + /** + * Unmap pages locally within core + * + * \param virt core-local address + * \param num_pages number of pages to unmap + */ + inline void unmap_local(addr_t virt, size_t num_pages) + { + ::unmap_local((Nova::Utcb *)Thread_base::myself()->utcb(), + virt, num_pages); } } diff --git a/base-nova/src/core/include/nova_util.h b/base-nova/src/core/include/nova_util.h index 8f17aa6ff..cae559e83 100644 --- a/base-nova/src/core/include/nova_util.h +++ b/base-nova/src/core/include/nova_util.h @@ -151,5 +151,56 @@ inline int map_local(Nova::Utcb *utcb, return 0; } +/** + * Unmap pages from the local address space + * + * \param utcb UTCB of the main thread + * \param start local virtual address + * \param num_pages number of pages to unmap + */ +inline void unmap_local(Nova::Utcb *utcb, + Genode::addr_t start, + Genode::size_t num_pages) +{ + if (verbose_local_map) + Genode::printf("::unmap_local: from %lx, %zd pages\n", + start, num_pages); + + using namespace Nova; + using namespace Genode; + Rights const rwx(true, true, true); + + Genode::addr_t end = start + (num_pages << get_page_size_log2()) - 1; + + while (true) { + Nova::Mem_crd crd(start >> 12, 32, rwx); + Nova::lookup(crd); + + if (!crd.is_null()) { + + if (verbose_local_map) + PINF("Unmapping local: %08lx base: %lx order: %lx size: %lx is null: %d", + start, crd.base(), crd.order(), + (0x1000UL << crd.order()), crd.is_null()); + + unmap_local(crd, true); + + start = (crd.base() << 12) /* base address of mapping */ + + (0x1000 << crd.order()); /* size of mapping */ + } else { + + /* This can happen if the region has never been touched */ + + if (verbose_local_map) + PINF("Nothing mapped at local: %08lx", start); + + start += 0x1000; + } + + if (start > end) + return; + } +} + #endif /* _NOVA_UTIL_H_ */ diff --git a/base-pistachio/src/core/include/map_local.h b/base-pistachio/src/core/include/map_local.h index 75ce274d2..40bcc7475 100644 --- a/base-pistachio/src/core/include/map_local.h +++ b/base-pistachio/src/core/include/map_local.h @@ -76,6 +76,17 @@ namespace Genode { } return true; } + + /** + * Unmap pages locally within core + * + * \param virt core-local address + * \param num_pages number of pages to unmap + */ + inline void unmap_local(addr_t virt, size_t num_pages) + { + PERR("unmap_local() called - not implemented yet"); + } } #endif /* _CORE__INCLUDE__MAP_LOCAL_H_ */ diff --git a/base/src/core/context_area.cc b/base/src/core/context_area.cc index 212845514..709d945b3 100644 --- a/base/src/core/context_area.cc +++ b/base/src/core/context_area.cc @@ -42,6 +42,8 @@ static Dataspace_component *context_ds[MAX_CORE_CONTEXTS]; */ class Context_area_rm_session : public Rm_session { + enum { verbose = false }; + public: /** @@ -59,18 +61,52 @@ class Context_area_rm_session : public Rm_session return (addr_t)0; } - if (!map_local(ds->phys_addr(), (addr_t)local_addr + - Native_config::context_area_virtual_base(), - ds->size() >> get_page_size_log2())) + addr_t core_local_addr = Native_config::context_area_virtual_base() + + (addr_t)local_addr; + + if (verbose) + PDBG("core_local_addr = %lx, phys_addr = %lx, size = 0x%zx", + core_local_addr, ds->phys_addr(), ds->size()); + + if (!map_local(ds->phys_addr(), core_local_addr, + ds->size() >> get_page_size_log2())) { + PERR("could not map phys %lx at local %lx", ds->phys_addr(), core_local_addr); return (addr_t)0; + } + + ds->assign_core_local_addr((void*)core_local_addr); return local_addr; } void detach(Local_addr local_addr) { - printf("context area detach from 0x%p - not implemented\n", - (void *)local_addr); + addr_t core_local_addr = Native_config::context_area_virtual_base() + + (addr_t)local_addr; + + Dataspace_component *ds = 0; + + /* find the dataspace component for the given address */ + for (unsigned i = 0; i < MAX_CORE_CONTEXTS; i++) { + if (context_ds[i] && + (core_local_addr >= context_ds[i]->core_local_addr()) && + (core_local_addr < (context_ds[i]->core_local_addr() + + context_ds[i]->size()))) { + ds = context_ds[i]; + break; + } + } + + if (!ds) { + PERR("dataspace for core context does not exist"); + return; + } + + if (verbose) + PDBG("core_local_addr = %lx, phys_addr = %lx, size = 0x%zx", + ds->core_local_addr(), ds->phys_addr(), ds->size()); + + Genode::unmap_local(ds->core_local_addr(), ds->size() >> get_page_size_log2()); } Pager_capability add_client(Thread_capability) { @@ -86,6 +122,8 @@ class Context_area_rm_session : public Rm_session class Context_area_ram_session : public Ram_session { + enum { verbose = false }; + public: Ram_dataspace_capability alloc(size_t size, bool cached) @@ -110,6 +148,9 @@ class Context_area_ram_session : public Ram_session return Ram_dataspace_capability(); } + if (verbose) + PDBG("phys_base = %p, size = 0x%zx", phys_base, size); + context_ds[i] = new (platform()->core_mem_alloc()) Dataspace_component(size, 0, (addr_t)phys_base, false, true, 0); @@ -117,7 +158,26 @@ class Context_area_ram_session : public Ram_session return static_cap_cast(cap); } - void free(Ram_dataspace_capability ds) { PDBG("not yet implemented"); } + void free(Ram_dataspace_capability ds) + { + Dataspace_component *dataspace_component = + dynamic_cast(Dataspace_capability::deref(ds)); + + for (unsigned i = 0; i < MAX_CORE_CONTEXTS; i++) + if (context_ds[i] == dataspace_component) { + context_ds[i] = 0; + break; + } + + void *phys_addr = (void*)dataspace_component->phys_addr(); + size_t size = dataspace_component->size(); + + if (verbose) + PDBG("phys_addr = %p, size = 0x%zx", phys_addr, size); + + destroy(platform()->core_mem_alloc(), dataspace_component); + platform_specific()->ram_alloc()->free(phys_addr, size); + } int ref_account(Ram_session_capability ram_session) { return 0; }