2012-05-30 20:13:09 +02:00
|
|
|
/*
|
|
|
|
* \brief RM- and pager implementations specific for base-hw and core
|
|
|
|
* \author Martin Stein
|
hw: restrict processor broadcast to TLB flushing
Removes the generic processor broadcast function call. By now, that call
was used for cross processor TLB maintance operations only. When core/kernel
gets its memory mapped on demand, and unmapped again, the previous cross
processor flush routine doesn't work anymore, because of a hen-egg problem.
The previous cross processor broadcast is realized using a thread constructed
by core running on top of each processor core. When constructing threads in
core, a dataspace for its thread context is constructed. Each constructed
RAM dataspace gets attached, zeroed out, and detached again. The detach
routine requires a TLB flush operation executed on each processor core.
Instead of executing a thread on each processor core, now a thread waiting
for a global TLB flush is removed from the scheduler queue, and gets attached
to a TLB flush queue of each processor. The processor local queue gets checked
whenever the kernel is entered. The last processor, which executed the TLB
flush, re-attaches the blocked thread to its scheduler queue again.
To ease uo the above described mechanism, a platform thread is now directly
associated with a platform pd object, instead of just associate it with the
kernel pd's id.
Ref #723
2014-04-28 20:36:00 +02:00
|
|
|
* \author Stefan Kalkowski
|
2012-05-30 20:13:09 +02:00
|
|
|
* \date 2012-02-12
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
2012-05-30 20:13:09 +02:00
|
|
|
*
|
|
|
|
* 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 */
|
2013-11-14 13:29:47 +01:00
|
|
|
#include <base/pager.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* core includes */
|
|
|
|
#include <rm_session_component.h>
|
|
|
|
#include <platform.h>
|
2013-09-18 13:12:32 +02:00
|
|
|
#include <platform_pd.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
#include <platform_thread.h>
|
2014-04-28 21:31:57 +02:00
|
|
|
#include <translation_table.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Rm_client **
|
|
|
|
***************/
|
|
|
|
|
2013-09-18 13:12:32 +02:00
|
|
|
void Rm_client::unmap(addr_t, addr_t virt_base, size_t size)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2014-03-07 15:58:01 +01:00
|
|
|
/* remove mapping from the translation table of the thread that we serve */
|
2013-11-15 13:47:55 +01:00
|
|
|
Platform_thread * const pt = (Platform_thread *)badge();
|
2014-04-28 21:31:57 +02:00
|
|
|
if (!pt || !pt->pd()) return;
|
|
|
|
|
|
|
|
Lock::Guard guard(*pt->pd()->lock());
|
|
|
|
|
|
|
|
Translation_table * const tt = pt->pd()->translation_table();
|
|
|
|
if (!tt) {
|
|
|
|
PWRN("failed to get translation table of RM client");
|
2013-08-30 16:02:31 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-04-28 21:31:57 +02:00
|
|
|
tt->remove_translation(virt_base, size,pt->pd()->page_slab());
|
2014-03-07 15:58:01 +01:00
|
|
|
|
|
|
|
/* update translation caches of all processors */
|
hw: restrict processor broadcast to TLB flushing
Removes the generic processor broadcast function call. By now, that call
was used for cross processor TLB maintance operations only. When core/kernel
gets its memory mapped on demand, and unmapped again, the previous cross
processor flush routine doesn't work anymore, because of a hen-egg problem.
The previous cross processor broadcast is realized using a thread constructed
by core running on top of each processor core. When constructing threads in
core, a dataspace for its thread context is constructed. Each constructed
RAM dataspace gets attached, zeroed out, and detached again. The detach
routine requires a TLB flush operation executed on each processor core.
Instead of executing a thread on each processor core, now a thread waiting
for a global TLB flush is removed from the scheduler queue, and gets attached
to a TLB flush queue of each processor. The processor local queue gets checked
whenever the kernel is entered. The last processor, which executed the TLB
flush, re-attaches the blocked thread to its scheduler queue again.
To ease uo the above described mechanism, a platform thread is now directly
associated with a platform pd object, instead of just associate it with the
kernel pd's id.
Ref #723
2014-04-28 20:36:00 +02:00
|
|
|
Kernel::update_pd(pt->pd()->id());
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 13:29:47 +01:00
|
|
|
/***************************
|
|
|
|
** Pager_activation_base **
|
|
|
|
***************************/
|
2012-05-30 20:13:09 +02:00
|
|
|
|
2013-11-14 13:29:47 +01:00
|
|
|
int Pager_activation_base::apply_mapping()
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2012-11-09 14:36:19 +01:00
|
|
|
/* prepare mapping */
|
2014-04-28 21:31:57 +02:00
|
|
|
Platform_pd * const pd = (Platform_pd*)_fault.pd;
|
|
|
|
|
|
|
|
Lock::Guard guard(*pd->lock());
|
|
|
|
|
|
|
|
Translation_table * const tt = pd->translation_table();
|
|
|
|
Page_slab * page_slab = pd->page_slab();
|
|
|
|
|
2014-02-24 16:27:22 +01:00
|
|
|
Page_flags const flags =
|
2013-11-14 13:29:47 +01:00
|
|
|
Page_flags::apply_mapping(_mapping.writable,
|
|
|
|
_mapping.write_combined,
|
|
|
|
_mapping.io_mem);
|
2012-11-05 18:32:04 +01:00
|
|
|
|
2014-04-28 21:31:57 +02:00
|
|
|
/* insert mapping into translation table */
|
|
|
|
try {
|
|
|
|
for (unsigned retry = 0; retry < 2; retry++) {
|
|
|
|
try {
|
|
|
|
tt->insert_translation(_mapping.virt_address, _mapping.phys_address,
|
|
|
|
1 << _mapping.size_log2, flags, page_slab);
|
|
|
|
return 0;
|
|
|
|
} catch(Page_slab::Out_of_slabs) {
|
|
|
|
page_slab->alloc_slab_block();
|
|
|
|
}
|
2013-08-30 16:02:31 +02:00
|
|
|
}
|
2014-04-28 21:31:57 +02:00
|
|
|
} catch(Allocator::Out_of_memory) {
|
|
|
|
PERR("Translation table needs to much RAM");
|
|
|
|
} catch(...) {
|
|
|
|
PERR("Invalid mapping %p -> %p (%zx)", (void*)_mapping.phys_address,
|
|
|
|
(void*)_mapping.virt_address, 1 << _mapping.size_log2);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
2014-04-28 21:31:57 +02:00
|
|
|
return -1;
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
2013-11-14 13:29:47 +01:00
|
|
|
|
|
|
|
void Pager_activation_base::entry()
|
|
|
|
{
|
|
|
|
/* get ready to receive faults */
|
|
|
|
_cap = Native_capability(thread_get_my_native_id(), 0);
|
|
|
|
_cap_valid.unlock();
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
/* await fault */
|
|
|
|
Pager_object * o;
|
|
|
|
while (1) {
|
|
|
|
Signal s = Signal_receiver::wait_for_signal();
|
|
|
|
o = dynamic_cast<Pager_object *>(s.context());
|
|
|
|
if (o) {
|
|
|
|
o->fault_occured(s);
|
|
|
|
break;
|
|
|
|
}
|
2014-03-12 16:29:44 +01:00
|
|
|
PWRN("unknown pager object");
|
2013-11-14 13:29:47 +01:00
|
|
|
}
|
|
|
|
/* fetch fault data */
|
2013-11-15 13:47:55 +01:00
|
|
|
Platform_thread * const pt = (Platform_thread *)o->badge();
|
|
|
|
if (!pt) {
|
2014-03-12 16:29:44 +01:00
|
|
|
PWRN("failed to get platform thread of faulter");
|
2013-11-15 13:47:55 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
unsigned const thread_id = pt->id();
|
2013-11-14 13:29:47 +01:00
|
|
|
typedef Kernel::Thread_reg_id Reg_id;
|
|
|
|
static addr_t const read_regs[] = {
|
|
|
|
Reg_id::FAULT_TLB, Reg_id::IP, Reg_id::FAULT_ADDR,
|
|
|
|
Reg_id::FAULT_WRITES, Reg_id::FAULT_SIGNAL };
|
|
|
|
enum { READS = sizeof(read_regs)/sizeof(read_regs[0]) };
|
|
|
|
void * const utcb = Thread_base::myself()->utcb()->base();
|
|
|
|
memcpy(utcb, read_regs, sizeof(read_regs));
|
2014-03-16 11:57:01 +01:00
|
|
|
addr_t * const values = (addr_t *)&_fault;
|
|
|
|
if (Kernel::access_thread_regs(thread_id, READS, 0, values)) {
|
2014-03-12 16:29:44 +01:00
|
|
|
PWRN("failed to read fault data");
|
2013-11-14 13:29:47 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* handle fault */
|
|
|
|
if (o->pager(*this)) { continue; }
|
|
|
|
if (apply_mapping()) {
|
2014-03-12 16:29:44 +01:00
|
|
|
PWRN("failed to apply mapping");
|
2013-11-14 13:29:47 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
o->fault_resolved();
|
|
|
|
}
|
|
|
|
}
|