core: Introduce 'Address_space' interface

The new core-internal 'Address_space' interface enables cores RM service
to flush mappings of a PD in which a given 'Rm_client' thread resides.
Prior this patch, each platform invented their own way to flush mappings
in the respective 'rm_session_support.cc' implementation. However, those
implementations used to deal poorly with some corner cases. In
particular, if a PD session was destroyed prior a RM session, the RM
session would try to use no longer existing PD session. The new
'Address_space' uses the just added weak-pointer mechanism to deal with
this issue.

Furthermore, the generic 'Rm_session_component::detach' function has
been improved to avoid duplicated unmap operations for platforms that
implement the 'Address_space' interface. Therefore, it is related to
issue #595. Right now, this is OKL4 only, but other platforms will follow.
This commit is contained in:
Norman Feske 2013-03-08 11:54:12 +01:00
parent 352f58b94b
commit 21de42c45d
30 changed files with 351 additions and 91 deletions

View File

@ -16,6 +16,7 @@
/* core includes */
#include <platform_thread.h>
#include <address_space.h>
/* Codezero includes */
#include <codezero/syscalls.h>
@ -23,7 +24,7 @@
namespace Genode {
class Platform_thread;
class Platform_pd
class Platform_pd : public Address_space
{
private:
@ -37,7 +38,6 @@ namespace Genode {
public:
/**
* Constructors
*/
@ -68,6 +68,13 @@ namespace Genode {
* Assign parent interface to protection domain
*/
int assign_parent(Native_capability parent) { return 0; }
/*****************************
** Address-space interface **
*****************************/
void flush(addr_t, size_t) { PDBG("not implemented"); }
};
}

View File

@ -19,6 +19,9 @@
#include <base/thread_state.h>
#include <base/native_types.h>
/* core includes */
#include <address_space.h>
namespace Genode {
class Platform_pd;
@ -30,19 +33,25 @@ namespace Genode {
enum { PD_NAME_MAX_LEN = 64 };
unsigned _tid; /* global codezero thread ID */
unsigned _space_id;
addr_t _utcb;
char _name[PD_NAME_MAX_LEN];
Pager_object *_pager;
unsigned _tid; /* global codezero thread ID */
unsigned _space_id;
Weak_ptr<Address_space> _address_space;
addr_t _utcb;
char _name[PD_NAME_MAX_LEN];
Pager_object *_pager;
/**
* Assign physical thread ID and UTCB address to thread
*
* This function is called from 'Platform_pd::bind_thread'.
*/
void _assign_physical_thread(unsigned tid, unsigned space_id, addr_t utcb) {
_tid = tid; _space_id = space_id; _utcb = utcb; }
void _assign_physical_thread(unsigned tid, unsigned space_id,
addr_t utcb,
Weak_ptr<Address_space> address_space)
{
_tid = tid; _space_id = space_id; _utcb = utcb;
_address_space = address_space;
}
public:
@ -100,6 +109,11 @@ namespace Genode {
*/
Thread_state state();
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -67,7 +67,8 @@ int Platform_pd::bind_thread(Platform_thread *thread)
}
addr_t utcb_addr = UTCB_VIRT_BASE + utcb_idx*sizeof(struct utcb);
thread->_assign_physical_thread(ids.tid, _space_id, utcb_addr);
thread->_assign_physical_thread(ids.tid, _space_id, utcb_addr,
this->Address_space::weak_ptr());
return 0;
}

View File

@ -98,6 +98,12 @@ void Platform_thread::cancel_blocking()
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _address_space;
}
Platform_thread::Platform_thread(const char *name, unsigned, addr_t,
int thread_id)
: _tid(THREAD_INVALID)

View File

@ -18,6 +18,7 @@
#define _CORE__INCLUDE__PLATFORM_PD_H_
#include <platform_thread.h>
#include <address_space.h>
namespace Fiasco {
#include <l4/sys/types.h>
@ -26,7 +27,7 @@ namespace Fiasco {
namespace Genode {
class Platform_thread;
class Platform_pd
class Platform_pd : public Address_space
{
private:
@ -176,6 +177,17 @@ namespace Genode {
int assign_parent(Native_capability parent) { return 0; }
int pd_id() const { return _pd_id; }
/*****************************
** Address-space interface **
*****************************/
/*
* On L4/Fiasco, we don't use directed unmap but rely on the
* in-kernel mapping database. See 'rm_session_support.cc'.
*/
void flush(addr_t, size_t) { PDBG("not implemented"); }
};
}

View File

@ -21,6 +21,7 @@
/* core includes */
#include <platform_pd.h>
#include <address_space.h>
/* Fiasco includes */
namespace Fiasco {
@ -122,6 +123,11 @@ namespace Genode {
*/
void affinity(unsigned) { }
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -145,6 +145,12 @@ void Platform_thread::cancel_blocking()
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _platform_pd->Address_space::weak_ptr();
}
Platform_thread::Platform_thread(const char *name, unsigned, addr_t, int thread_id)
: _thread_id(thread_id), _l4_thread_id(L4_INVALID_ID), _pager(0)
{

View File

@ -27,6 +27,7 @@
/* core includes */
#include <cap_mapping.h>
#include <address_space.h>
/* Fiasco.OC includes */
namespace Fiasco {
@ -36,7 +37,7 @@ namespace Fiasco {
namespace Genode {
class Platform_thread;
class Platform_pd
class Platform_pd : public Address_space
{
private:
@ -97,11 +98,23 @@ namespace Genode {
*/
int assign_parent(Native_capability parent);
/*******************************
** Fiasco-specific Accessors **
*******************************/
Native_capability native_task() { return _task.local; }
/*****************************
** Address-space interface **
*****************************/
/*
* On Fiasco.OC, we don't use directed unmap but rely on the
* in-kernel mapping database. See 'rm_session_support.cc'.
*/
void flush(addr_t, size_t) { PDBG("not implemented"); }
};
}

View File

@ -24,6 +24,7 @@
#include <platform_pd.h>
#include <cap_session_component.h>
#include <cap_mapping.h>
#include <address_space.h>
namespace Genode {
@ -134,6 +135,11 @@ namespace Genode {
*/
void affinity(unsigned cpu);
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -237,6 +237,12 @@ void Platform_thread::_finalize_construction(const char *name)
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _platform_pd->Address_space::weak_ptr();
}
Platform_thread::Platform_thread(const char *name,
unsigned prio)
: _core_thread(false),

View File

@ -19,6 +19,9 @@
#include <base/thread_state.h>
#include <base/native_types.h>
/* core includes */
#include <address_space.h>
namespace Genode {
class Platform_pd;
@ -80,6 +83,11 @@ namespace Genode {
*/
Thread_state state();
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -73,6 +73,13 @@ unsigned long Platform_thread::pager_object_badge() const
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
PWRN("not implemented");
return Weak_ptr<Address_space>();
}
Platform_thread::Platform_thread(const char *name, unsigned, addr_t,
int thread_id)
{

View File

@ -20,6 +20,7 @@
/* Core includes */
#include <platform.h>
#include <platform_thread.h>
#include <address_space.h>
namespace Kernel
{
@ -34,7 +35,7 @@ namespace Genode
/**
* Platform specific part of a Genode protection domain
*/
class Platform_pd
class Platform_pd : public Address_space
{
unsigned _id; /* ID of our kernel object */
Native_capability _parent; /* our parent interface */
@ -77,9 +78,9 @@ namespace Genode
{
/* annotate that we've got a main thread from now on */
_main_thread = t->id();
return t->join_pd(_id, 1);
return t->join_pd(_id, 1, Address_space::weak_ptr());
}
return t->join_pd(_id, 0);
return t->join_pd(_id, 0, Address_space::weak_ptr());
}
/**
@ -98,6 +99,13 @@ namespace Genode
_parent = parent;
return 0;
}
/*****************************
** Address-space interface **
*****************************/
void flush(addr_t, size_t) { PDBG("not implemented"); }
};
}

View File

@ -24,6 +24,7 @@
/* core includes */
#include <assert.h>
#include <address_space.h>
namespace Genode {
@ -43,6 +44,7 @@ namespace Genode {
Thread_base * _thread_base;
size_t _stack_size;
unsigned _pd_id;
Weak_ptr<Address_space> _address_space;
unsigned _id;
Rm_client * _rm_client;
bool _main_thread;
@ -91,7 +93,8 @@ namespace Genode {
* \retval 0 on success
* \retval <0 otherwise
*/
int join_pd(unsigned const pd_id, bool const main_thread);
int join_pd(unsigned const pd_id, bool const main_thread,
Weak_ptr<Address_space> address_space);
/**
* Run this thread
@ -142,6 +145,11 @@ namespace Genode {
void affinity(unsigned cpu) {
kernel_log() << __PRETTY_FUNCTION__ << ": not implemented\n"; };
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/***************
** Accessors **

View File

@ -32,6 +32,12 @@ bool Platform_thread::_attaches_utcb_by_itself()
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _address_space;
}
Platform_thread::~Platform_thread()
{
/* detach UTCB if main thread outside core */
@ -102,14 +108,16 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority,
}
int Platform_thread::join_pd(unsigned const pd_id, bool const main_thread)
int Platform_thread::join_pd(unsigned const pd_id, bool const main_thread,
Weak_ptr<Address_space> address_space)
{
/* check if we're already in another PD */
if (_pd_id && _pd_id != pd_id) return -1;
/* denote configuration for start method */
_pd_id = pd_id;
_main_thread = main_thread;
_pd_id = pd_id;
_main_thread = main_thread;
_address_space = address_space;
return 0;
}

View File

@ -15,6 +15,7 @@
#define _CORE__INCLUDE__PLATFORM_PD_H_
#include <platform_thread.h>
#include <address_space.h>
/*
* Must be initialized by the startup code,
@ -25,7 +26,7 @@ extern Genode::addr_t __core_pd_sel;
namespace Genode {
class Platform_thread;
class Platform_pd
class Platform_pd : public Address_space
{
private:
@ -88,6 +89,17 @@ namespace Genode {
* \return PD selector
*/
static addr_t pd_core_sel() { return __core_pd_sel; }
/*****************************
** Address-space interface **
*****************************/
/*
* On NOVA, we don't use directed unmap but rely on the
* in-kernel mapping database. See 'rm_session_support.cc'.
*/
void flush(addr_t, size_t) { PDBG("not implemented"); }
};
}

View File

@ -22,6 +22,9 @@
#include <base/thread.h>
#include <base/pager.h>
/* core includes */
#include <address_space.h>
namespace Genode {
class Platform_pd;
@ -98,6 +101,11 @@ namespace Genode {
*/
Thread_state state();
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -309,6 +309,12 @@ unsigned long Platform_thread::pager_object_badge() const
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _pd->Address_space::weak_ptr();
}
Platform_thread::Platform_thread(const char *name, unsigned, int thread_id)
:
_pd(0), _pager(0), _id_base(cap_selector_allocator()->alloc(1)),

View File

@ -14,7 +14,9 @@
#ifndef _CORE__INCLUDE__PLATFORM_PD_H_
#define _CORE__INCLUDE__PLATFORM_PD_H_
/* core includes */
#include <platform_thread.h>
#include <address_space.h>
namespace Okl4 { extern "C" {
#include <l4/types.h>
@ -23,7 +25,7 @@ namespace Okl4 { extern "C" {
namespace Genode {
class Platform_thread;
class Platform_pd
class Platform_pd : public Address_space
{
private:
@ -185,6 +187,13 @@ namespace Genode {
void space_pager(Platform_thread *pd);
int pd_id() const { return _pd_id; }
/*****************************
** Address-space interface **
*****************************/
void flush(addr_t, size_t);
};
}

View File

@ -21,6 +21,7 @@
/* core includes */
#include <platform_pd.h>
#include <address_space.h>
namespace Genode {
@ -110,6 +111,11 @@ namespace Genode {
*/
Thread_state state();
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -257,6 +257,69 @@ void Platform_pd::_setup_address_space()
}
static const bool verbose_unmap = false;
static void unmap_log2_range(unsigned pd_id, addr_t base, size_t size_log2)
{
using namespace Okl4;
L4_Fpage_t fpage = L4_FpageLog2(base, size_log2);
L4_FpageAddRightsTo(&fpage, L4_FullyAccessible);
int ret = L4_UnmapFpage(L4_SpaceId(pd_id), fpage);
if (ret != 1)
PERR("could not unmap page at %p from space %x (Error Code %ld)",
(void *)base, pd_id, L4_ErrorCode());
}
void Platform_pd::flush(addr_t addr, size_t size)
{
using namespace Okl4;
L4_Word_t remaining_size = size;
L4_Word_t size_log2 = get_page_size_log2();
if (verbose_unmap)
printf("PD %d: unmap [%lx,%lx)\n", _pd_id, addr, addr + size);
/*
* Let unmap granularity ('size_log2') grow
*/
while (remaining_size >= (1UL << size_log2)) {
enum { SIZE_LOG2_MAX = 22 /* 4M */ };
/* issue 'unmap' for the current address if flexpage aligned */
if (addr & (1 << size_log2)) {
unmap_log2_range(_pd_id, addr, size_log2);
remaining_size -= 1 << size_log2;
addr += 1 << size_log2;
}
/* increase flexpage size */
size_log2++;
}
/*
* Let unmap granularity ('size_log2') shrink
*/
while (remaining_size > 0) {
if (remaining_size >= (1UL << size_log2)) {
unmap_log2_range(_pd_id, addr, size_log2);
remaining_size -= 1 << size_log2;
addr += 1 << size_log2;
}
/* decrease flexpage size */
size_log2--;
}
}
Platform_pd::Platform_pd(bool core)
: _space_pager(0)
{

View File

@ -178,6 +178,12 @@ unsigned long Platform_thread::pager_object_badge() const
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _platform_pd->Address_space::weak_ptr();
}
Platform_thread::Platform_thread(const char *name, unsigned prio, addr_t, int thread_id)
: _thread_id(thread_id), _l4_thread_id(L4_nilthread), _platform_pd(0),
_priority(prio), _pager(0)

View File

@ -17,74 +17,13 @@
/* core includes */
#include <rm_session_component.h>
/* OKL4 includes */
namespace Okl4 { extern "C" {
#include <l4/types.h>
#include <l4/space.h>
#include <l4/ipc.h>
} }
using namespace Genode;
using namespace Okl4;
static const bool verbose_unmap = false;
static void unmap_log2_range(L4_SpaceId_t space_id, L4_Word_t base, L4_Word_t size_log2)
{
L4_Fpage_t fpage = L4_FpageLog2(base, size_log2);
L4_FpageAddRightsTo(&fpage, L4_FullyAccessible);
int ret = L4_UnmapFpage(space_id, fpage);
if (ret != 1)
PERR("could not unmap page at %p from space %lx (Error Code %ld)",
(void *)base, space_id.raw, L4_ErrorCode());
}
void Rm_client::unmap(addr_t, addr_t virt_base, size_t size)
{
L4_ThreadId_t tid = { raw : badge() };
L4_SpaceId_t space_id = { raw: L4_ThreadNo(tid) >> Thread_id_bits::THREAD };
L4_Word_t addr = virt_base;
L4_Word_t remaining_size = size;
L4_Word_t size_log2 = get_page_size_log2();
Locked_ptr<Address_space> locked_address_space(_address_space);
if (verbose_unmap)
printf("RM client %p (%lx) unmap [%lx,%lx)\n",
this, badge(), virt_base, virt_base + size);
/*
* Let unmap granularity ('size_log2') grow
*/
while (remaining_size >= (1UL << size_log2)) {
enum { SIZE_LOG2_MAX = 22 /* 4M */ };
/* issue 'unmap' for the current address if flexpage aligned */
if (addr & (1 << size_log2)) {
unmap_log2_range(space_id, addr, size_log2);
remaining_size -= 1 << size_log2;
addr += 1 << size_log2;
}
/* increase flexpage size */
size_log2++;
}
/*
* Let unmap granularity ('size_log2') shrink
*/
while (remaining_size > 0) {
if (remaining_size >= (1UL << size_log2)) {
unmap_log2_range(space_id, addr, size_log2);
remaining_size -= 1 << size_log2;
addr += 1 << size_log2;
}
/* decrease flexpage size */
size_log2--;
}
if (locked_address_space.is_valid())
locked_address_space->flush(virt_base, size);
}

View File

@ -15,6 +15,7 @@
#define _CORE__INCLUDE__PLATFORM_PD_H_
#include <platform_thread.h>
#include <address_space.h>
namespace Pistachio {
#include <l4/types.h>
@ -23,7 +24,7 @@ namespace Pistachio {
namespace Genode {
class Platform_thread;
class Platform_pd
class Platform_pd : public Address_space
{
private:
@ -216,6 +217,17 @@ namespace Genode {
int assign_parent(Native_capability parent) { return 0; }
int pd_id() const { return _pd_id; }
/*****************************
** Address-space interface **
*****************************/
/*
* On Pistachio, we don't use directed unmap but rely on the
* in-kernel mapping database. See 'rm_session_support.cc'.
*/
void flush(addr_t, size_t) { PDBG("not implemented"); }
};
}

View File

@ -21,6 +21,7 @@
/* core includes */
#include <platform_pd.h>
#include <address_space.h>
/* Pistachio includes */
namespace Pistachio {
@ -114,6 +115,11 @@ namespace Genode {
*/
Thread_state state();
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
/************************
** Accessor functions **

View File

@ -226,6 +226,12 @@ void Platform_thread::cancel_blocking()
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _platform_pd->Address_space::weak_ptr();
}
Platform_thread::Platform_thread(const char *name, unsigned prio, addr_t, int id)
: _thread_id(id), _l4_thread_id(L4_nilthread), _priority(prio), _pager(0)
{

View File

@ -100,6 +100,7 @@ namespace Genode {
class Out_of_metadata : public Attach_failed { };
class Invalid_thread : public Exception { };
class Unbound_thread : public Exception { };
/**
* Destructor
@ -156,6 +157,7 @@ namespace Genode {
* \param thread thread that will be paged
* \throw Invalid_thread
* \throw Out_of_metadata
* \throw Unbound_thread
* \return capability to be used for handling page faults
*
* This method must be called at least once to establish a valid

View File

@ -0,0 +1,33 @@
/*
* \brief Interface for flushing mapping from a protection domain
* \author Norman Feske
* \date 2013-03-07
*/
/*
* Copyright (C) 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.
*/
#ifndef _CORE__INCLUDE__ADDRESS_SPACE_H_
#define _CORE__INCLUDE__ADDRESS_SPACE_H_
#include <base/stdint.h>
#include <lifetime.h>
namespace Genode { struct Address_space; }
struct Genode::Address_space : Genode::Volatile_object<Genode::Address_space>
{
/**
* Flush memory mappings of virtual address range
*
* \param virt_addr start address of range to flush
* \param size size of range in bytes, must be a multiple of page size
*/
virtual void flush(addr_t virt_addr, size_t size) = 0;
};
#endif /* _CORE__INCLUDE__ADDRESS_SPACE_H_ */

View File

@ -32,10 +32,10 @@
#include <platform.h>
#include <dataspace_component.h>
#include <util.h>
#include <address_space.h>
namespace Genode {
class Dataspace_component;
class Rm_session_component;
class Rm_client;
@ -185,6 +185,10 @@ namespace Genode {
class Rm_client : public Pager_object, public Rm_member, public Rm_faulter,
public List<Rm_client>::Element
{
private:
Weak_ptr<Address_space> _address_space;
public:
/**
@ -194,8 +198,11 @@ namespace Genode {
* \param badge pager-object badge used of identifying the client
* when a page-fault occurs
*/
Rm_client(Rm_session_component *session, unsigned long badge) :
Pager_object(badge), Rm_member(session), Rm_faulter(this) { }
Rm_client(Rm_session_component *session, unsigned long badge,
Weak_ptr<Address_space> &address_space)
:
Pager_object(badge), Rm_member(session), Rm_faulter(this),
_address_space(address_space) { }
int pager(Ipc_pager &pager);
@ -203,6 +210,11 @@ namespace Genode {
* Flush memory mappings for the specified virtual address range
*/
void unmap(addr_t core_local_base, addr_t virt_base, size_t size);
bool has_same_address_space(Rm_client const &other)
{
return other._address_space == _address_space;
}
};

View File

@ -545,7 +545,9 @@ void Rm_session_component::detach(Local_addr local_addr)
* Go through all RM clients using the RM session. For each RM client, we
* need to unmap the referred region from its virtual address space.
*/
for (Rm_client *rc = _clients.first(); rc; rc = rc->List<Rm_client>::Element::next()) {
Rm_client *prev_rc = 0;
Rm_client *rc = _clients.first();
for (; rc; rc = rc->List<Rm_client>::Element::next(), prev_rc = rc) {
/*
* XXX Unmapping managed dataspaces on kernels, which take a core-
@ -563,6 +565,23 @@ void Rm_session_component::detach(Local_addr local_addr)
break;
}
/*
* Don't unmap from the same address space twice. If multiple threads
* reside in one PD, each thread will have a corresponding 'Rm_client'
* object. Consequenlty, an unmap operation referring to the PD is
* issued multiple times, one time for each thread. By comparing the
* membership to the thread's respective address spaces, we reduce
* superfluous unmap operations.
*
* Note that the list of 'Rm_client' object may contain threads of
* different address spaces in any order. So superfluous unmap
* operations can still happen if 'Rm_client' objects of one PD are
* interleaved with 'Rm_client' objects of another PD. In practice,
* however, this corner case is rare.
*/
if (prev_rc && prev_rc->has_same_address_space(*rc))
continue;
rc->unmap(dsc->core_local_addr() + region->offset(),
region->base(), region->size());
}
@ -588,6 +607,7 @@ void Rm_session_component::detach(Local_addr local_addr)
Pager_capability Rm_session_component::add_client(Thread_capability thread)
{
unsigned long badge;
Weak_ptr<Address_space> address_space;
{
/* lookup thread and setup correct parameters */
@ -597,13 +617,17 @@ Pager_capability Rm_session_component::add_client(Thread_capability thread)
/* determine identification of client when faulting */
badge = cpu_thread->platform_thread()->pager_object_badge();
address_space = cpu_thread->platform_thread()->address_space();
if (!Locked_ptr<Address_space>(address_space).is_valid())
throw Unbound_thread();
}
/* serialize access */
Lock::Guard lock_guard(_lock);
Rm_client *cl;
try { cl = new(&_client_slab) Rm_client(this, badge); }
try { cl = new(&_client_slab) Rm_client(this, badge, address_space); }
catch (Allocator::Out_of_memory) { throw Out_of_metadata(); }
catch (Cpu_session::Thread_creation_failed) { throw Out_of_metadata(); }
catch (Thread_base::Stack_alloc_failed) { throw Out_of_metadata(); }