From b2d92f3d943ba0dbf4f11b63f7191924f41b4905 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 27 Feb 2013 15:58:58 +0100 Subject: [PATCH] nova: optimize unmap path Directly unmap memory range instead of looking first it up and then unmap it. Prerequisite for #675 --- base-nova/src/core/include/nova_util.h | 82 ++++++++++++------------ base-nova/src/core/rm_session_support.cc | 46 ++----------- 2 files changed, 47 insertions(+), 81 deletions(-) diff --git a/base-nova/src/core/include/nova_util.h b/base-nova/src/core/include/nova_util.h index 024b2a04c..e6bb70707 100644 --- a/base-nova/src/core/include/nova_util.h +++ b/base-nova/src/core/include/nova_util.h @@ -2,6 +2,7 @@ * \brief NOVA-specific convenience functions * \author Norman Feske * \author Sebastian Sumpf + * \author Alexander Boettcher * \date 2010-01-19 */ @@ -86,6 +87,20 @@ inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { return map_local(utcb, crd, crd, true); } +/** + * Find least significant set bit in value + */ +inline unsigned char +lsb_bit(unsigned long const &value, unsigned char const shift = 0) +{ + unsigned long const scan = value >> shift; + if (scan == 0) return 0; + + unsigned char pos = __builtin_ctzl(scan); + unsigned char res = shift ? pos + shift : pos; + return res; +} + /** * Remap pages in the local address space * @@ -123,19 +138,10 @@ inline int map_local(Nova::Utcb *utcb, */ addr_t const common_bits = from_curr | to_curr; - /* - * Find highest clear bit in 'diff', starting from the least - * significant candidate. We can skip all bits lower then - * 'get_page_size_log2()' because they are not relevant as flexpage - * size (and are always zero). - */ - size_t order = get_page_size_log2(); - for (; order < 32 && !(common_bits & (1UL << order)); order++); - - /* - * Look if flexpage fits into both 'from' and 'to' address range - */ + /* find least set bit in common bits */ + size_t order = lsb_bit(common_bits, get_page_size_log2()); + /* look if flexpage fits into both 'from' and 'to' address range */ if ((from_end - from_curr) < (1UL << order)) order = log2(from_end - from_curr); @@ -165,48 +171,42 @@ inline int map_local(Nova::Utcb *utcb, * \param utcb UTCB of the main thread * \param start local virtual address * \param num_pages number of pages to unmap + * \param self unmap from this pd or solely from other pds */ -inline void unmap_local(Nova::Utcb *utcb, - Genode::addr_t start, - Genode::size_t num_pages) +inline void unmap_local(Nova::Utcb *utcb, Genode::addr_t start, + Genode::size_t num_pages, + bool const self = true) { - 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; + Genode::addr_t base = start >> get_page_size_log2(); - while (true) { - Nova::Mem_crd crd(start >> 12, 32, rwx); - Nova::lookup(crd); + if (start & (get_page_size() - 1)) { + PERR("unmap failed - unaligned address specified"); + return; + } - if (!crd.is_null()) { + if (verbose_local_map) + PINF("Unmapping local: range 0x%lx+0x%zx", base, num_pages); - 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()); + Nova::Rights const rwx = Nova::Rights(true, true, true); - unmap_local(crd, true); + while (num_pages) { + unsigned char const base_bit = lsb_bit(base); + unsigned char const order_bit = min(log2(num_pages), 31U); + unsigned char const order = min(order_bit, base_bit); - start = (crd.base() << 12) /* base address of mapping */ - + (0x1000 << crd.order()); /* size of mapping */ - } else { + Mem_crd const crd(base, order, rwx); - /* This can happen if the region has never been touched */ + if (verbose_local_map) + PINF("Unmapping local: 0x%lx+0x%lx", crd.base(), + 1UL << crd.order()); - if (verbose_local_map) - PINF("Nothing mapped at local: %08lx", start); + unmap_local(crd, self); - start += 0x1000; - } - - if (start > end) - return; + num_pages -= 1UL << order; + base += 1UL << order; } } diff --git a/base-nova/src/core/rm_session_support.cc b/base-nova/src/core/rm_session_support.cc index d761cb1b7..e5d6b0617 100644 --- a/base-nova/src/core/rm_session_support.cc +++ b/base-nova/src/core/rm_session_support.cc @@ -12,53 +12,19 @@ * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include -#include - /* core includes */ #include #include using namespace Genode; -static const bool verbose = false; - - -void Rm_client::unmap(addr_t core_local_base, addr_t virt_base, size_t size) +void Rm_client::unmap(addr_t core_local_base, addr_t, size_t size) { - addr_t const core_local_end = core_local_base + (size - 1); - off_t const core_to_virt = virt_base - core_local_base; + using namespace Nova; - Nova::Rights rwx(true, true, true); + Utcb * utcb = reinterpret_cast(Genode::Thread_base::myself()->utcb()); - while (true) { - Nova::Mem_crd crd(core_local_base >> 12, 32, rwx); - Nova::lookup(crd); - - if (!crd.is_null()) { - - if (verbose) - PINF("Unmapping local: %08lx virt: %08lx base: %lx order: %lx size: %lx is null: %d", - core_local_base, core_local_base + core_to_virt, crd.base(), crd.order(), - (0x1000UL << crd.order()), crd.is_null()); - - unmap_local(crd, false); - - core_local_base = (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) - PINF("Nothing mapped at local: %08lx virt: %08lx", - core_local_base, core_local_base + core_to_virt); - - core_local_base += 0x1000; - } - - if (core_local_base > core_local_end) - return; - } + unmap_local(utcb, trunc_page(core_local_base), + (round_page(core_local_base + size) - + trunc_page(core_local_base)) / get_page_size(), false); }