nova: optimize unmap path
Directly unmap memory range instead of looking first it up and then unmap it. Prerequisite for #675
This commit is contained in:
parent
974c5442c6
commit
b2d92f3d94
|
@ -2,6 +2,7 @@
|
||||||
* \brief NOVA-specific convenience functions
|
* \brief NOVA-specific convenience functions
|
||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2010-01-19
|
* \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); }
|
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
|
* 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;
|
addr_t const common_bits = from_curr | to_curr;
|
||||||
|
|
||||||
/*
|
/* find least set bit in common bits */
|
||||||
* Find highest clear bit in 'diff', starting from the least
|
size_t order = lsb_bit(common_bits, get_page_size_log2());
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* look if flexpage fits into both 'from' and 'to' address range */
|
||||||
if ((from_end - from_curr) < (1UL << order))
|
if ((from_end - from_curr) < (1UL << order))
|
||||||
order = log2(from_end - from_curr);
|
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 utcb UTCB of the main thread
|
||||||
* \param start local virtual address
|
* \param start local virtual address
|
||||||
* \param num_pages number of pages to unmap
|
* \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,
|
inline void unmap_local(Nova::Utcb *utcb, Genode::addr_t start,
|
||||||
Genode::addr_t start,
|
Genode::size_t num_pages,
|
||||||
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 Nova;
|
||||||
using namespace Genode;
|
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) {
|
if (start & (get_page_size() - 1)) {
|
||||||
Nova::Mem_crd crd(start >> 12, 32, rwx);
|
PERR("unmap failed - unaligned address specified");
|
||||||
Nova::lookup(crd);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!crd.is_null()) {
|
if (verbose_local_map)
|
||||||
|
PINF("Unmapping local: range 0x%lx+0x%zx", base, num_pages);
|
||||||
|
|
||||||
if (verbose_local_map)
|
Nova::Rights const rwx = Nova::Rights(true, true, true);
|
||||||
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);
|
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 */
|
Mem_crd const crd(base, order, rwx);
|
||||||
+ (0x1000 << crd.order()); /* size of mapping */
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* 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)
|
unmap_local(crd, self);
|
||||||
PINF("Nothing mapped at local: %08lx", start);
|
|
||||||
|
|
||||||
start += 0x1000;
|
num_pages -= 1UL << order;
|
||||||
}
|
base += 1UL << order;
|
||||||
|
|
||||||
if (start > end)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,53 +12,19 @@
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/printf.h>
|
|
||||||
#include <base/ipc_pager.h>
|
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <rm_session_component.h>
|
#include <rm_session_component.h>
|
||||||
#include <nova_util.h>
|
#include <nova_util.h>
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
static const bool verbose = false;
|
void Rm_client::unmap(addr_t core_local_base, addr_t, size_t size)
|
||||||
|
|
||||||
|
|
||||||
void Rm_client::unmap(addr_t core_local_base, addr_t virt_base, size_t size)
|
|
||||||
{
|
{
|
||||||
addr_t const core_local_end = core_local_base + (size - 1);
|
using namespace Nova;
|
||||||
off_t const core_to_virt = virt_base - core_local_base;
|
|
||||||
|
|
||||||
Nova::Rights rwx(true, true, true);
|
Utcb * utcb = reinterpret_cast<Utcb *>(Genode::Thread_base::myself()->utcb());
|
||||||
|
|
||||||
while (true) {
|
unmap_local(utcb, trunc_page(core_local_base),
|
||||||
Nova::Mem_crd crd(core_local_base >> 12, 32, rwx);
|
(round_page(core_local_base + size) -
|
||||||
Nova::lookup(crd);
|
trunc_page(core_local_base)) / get_page_size(), false);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue