2013-12-17 18:10:02 +01:00
|
|
|
/*
|
2014-03-11 01:21:56 +01:00
|
|
|
* \brief A multiplexable common instruction processor
|
2013-12-17 18:10:02 +01:00
|
|
|
* \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
|
2013-12-17 18:10:02 +01:00
|
|
|
* \date 2014-01-14
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 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.
|
|
|
|
*/
|
|
|
|
|
2014-03-03 15:29:05 +01:00
|
|
|
#ifndef _KERNEL__PROCESSOR_H_
|
|
|
|
#define _KERNEL__PROCESSOR_H_
|
2013-12-17 18:10:02 +01:00
|
|
|
|
|
|
|
/* core includes */
|
2014-05-21 15:52:05 +02:00
|
|
|
#include <timer.h>
|
2014-03-03 00:12:53 +01:00
|
|
|
#include <processor_driver.h>
|
2014-03-11 01:21:56 +01:00
|
|
|
#include <kernel/scheduler.h>
|
2013-12-17 18:10:02 +01:00
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
2014-04-09 12:14:38 +02:00
|
|
|
using Genode::Processor_driver;
|
|
|
|
using Genode::Processor_lazy_state;
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
/**
|
2014-03-11 01:21:56 +01:00
|
|
|
* A single user of a multiplexable processor
|
2013-12-17 18:10:02 +01:00
|
|
|
*/
|
2014-03-11 01:21:56 +01:00
|
|
|
class Processor_client;
|
2013-12-17 18:10:02 +01:00
|
|
|
|
2014-05-02 18:14:51 +02:00
|
|
|
/**
|
|
|
|
* Ability to do a domain update on all processors
|
|
|
|
*/
|
|
|
|
class Processor_domain_update;
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
/**
|
2014-03-11 01:21:56 +01:00
|
|
|
* Multiplexes a single processor to multiple processor clients
|
2013-12-17 18:10:02 +01:00
|
|
|
*/
|
2014-03-11 01:21:56 +01:00
|
|
|
typedef Scheduler<Processor_client> Processor_scheduler;
|
2013-12-17 18:10:02 +01:00
|
|
|
|
|
|
|
/**
|
2014-03-11 01:21:56 +01:00
|
|
|
* A multiplexable common instruction processor
|
2013-12-17 18:10:02 +01:00
|
|
|
*/
|
2014-03-11 01:21:56 +01:00
|
|
|
class Processor;
|
2013-12-17 18:10:02 +01:00
|
|
|
}
|
|
|
|
|
2014-05-02 18:14:51 +02:00
|
|
|
class Kernel::Processor_domain_update
|
|
|
|
:
|
|
|
|
public Double_list_item<Processor_domain_update>
|
|
|
|
{
|
|
|
|
friend class Processor_domain_update_list;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
bool _pending[PROCESSORS];
|
|
|
|
unsigned _domain_id;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Domain-update back-end
|
|
|
|
*/
|
|
|
|
void _domain_update()
|
|
|
|
{
|
|
|
|
Processor_driver::flush_tlb_by_pid(_domain_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Perform the domain update on the executing processors
|
|
|
|
*/
|
|
|
|
void _perform_locally();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
|
|
|
Processor_domain_update()
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < PROCESSORS; i++) { _pending[i] = false; }
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Perform the domain update on all processors
|
|
|
|
*
|
|
|
|
* \param domain_id kernel name of targeted domain
|
|
|
|
*
|
|
|
|
* \return wether the update blocks and reports back on completion
|
|
|
|
*/
|
|
|
|
bool _perform(unsigned const domain_id);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notice that the update isn't pending on any processor anymore
|
|
|
|
*/
|
|
|
|
virtual void _processor_domain_update_unblocks() = 0;
|
|
|
|
};
|
|
|
|
|
2014-03-11 01:21:56 +01:00
|
|
|
class Kernel::Processor_client : public Processor_scheduler::Item
|
2013-12-17 18:10:02 +01:00
|
|
|
{
|
2014-03-11 01:21:56 +01:00
|
|
|
protected:
|
|
|
|
|
2014-04-09 12:14:38 +02:00
|
|
|
Processor * _processor;
|
|
|
|
Processor_lazy_state _lazy_state;
|
|
|
|
|
2014-03-11 01:21:56 +01:00
|
|
|
/**
|
|
|
|
* Handle an interrupt exception that occured during execution
|
|
|
|
*
|
|
|
|
* \param processor_id kernel name of targeted processor
|
|
|
|
*/
|
|
|
|
void _interrupt(unsigned const processor_id);
|
2013-12-17 18:10:02 +01:00
|
|
|
|
|
|
|
/**
|
2014-03-11 01:21:56 +01:00
|
|
|
* Insert context into the processor scheduling
|
2013-12-17 18:10:02 +01:00
|
|
|
*/
|
2014-03-11 01:21:56 +01:00
|
|
|
void _schedule();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove context from the processor scheduling
|
|
|
|
*/
|
|
|
|
void _unschedule();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Yield currently scheduled processor share of the context
|
|
|
|
*/
|
|
|
|
void _yield();
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
public:
|
|
|
|
|
2014-03-11 01:21:56 +01:00
|
|
|
/**
|
|
|
|
* Handle an exception that occured during execution
|
|
|
|
*
|
|
|
|
* \param processor_id kernel name of targeted processor
|
|
|
|
*/
|
|
|
|
virtual void exception(unsigned const processor_id) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Continue execution
|
|
|
|
*
|
|
|
|
* \param processor_id kernel name of targeted processor
|
|
|
|
*/
|
|
|
|
virtual void proceed(unsigned const processor_id) = 0;
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param processor kernel object of targeted processor
|
2014-03-11 01:21:56 +01:00
|
|
|
* \param priority scheduling priority
|
2013-12-17 18:10:02 +01:00
|
|
|
*/
|
2014-03-11 01:21:56 +01:00
|
|
|
Processor_client(Processor * const processor, Priority const priority)
|
2013-12-17 18:10:02 +01:00
|
|
|
:
|
2014-03-11 01:21:56 +01:00
|
|
|
Processor_scheduler::Item(priority),
|
2014-05-02 18:14:51 +02:00
|
|
|
_processor(processor)
|
2014-03-11 01:21:56 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*/
|
|
|
|
~Processor_client()
|
2013-12-17 18:10:02 +01:00
|
|
|
{
|
2014-03-11 01:21:56 +01:00
|
|
|
if (!_scheduled()) { return; }
|
|
|
|
_unschedule();
|
2013-12-17 18:10:02 +01:00
|
|
|
}
|
2014-04-09 12:14:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
Processor_lazy_state * lazy_state() { return &_lazy_state; }
|
2013-12-17 18:10:02 +01:00
|
|
|
};
|
|
|
|
|
2014-03-03 00:12:53 +01:00
|
|
|
class Kernel::Processor : public Processor_driver
|
2013-12-17 18:10:02 +01:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2014-03-06 13:55:56 +01:00
|
|
|
unsigned const _id;
|
2013-12-17 18:10:02 +01:00
|
|
|
Processor_scheduler _scheduler;
|
2014-03-11 12:53:42 +01:00
|
|
|
bool _ip_interrupt_pending;
|
2014-05-21 15:52:05 +02:00
|
|
|
Timer * const _timer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset the scheduling timer for a new scheduling interval
|
|
|
|
*/
|
|
|
|
void _reset_timer()
|
|
|
|
{
|
|
|
|
unsigned const tics = _timer->ms_to_tics(USER_LAP_TIME_MS);
|
|
|
|
_timer->start_one_shot(tics, _id);
|
|
|
|
}
|
2013-12-17 18:10:02 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
2014-03-06 13:55:56 +01:00
|
|
|
*
|
2014-03-11 01:21:56 +01:00
|
|
|
* \param id kernel name of the processor object
|
|
|
|
* \param idle_client client that gets scheduled on idle
|
2014-05-21 15:52:05 +02:00
|
|
|
* \param timer timer that is used for scheduling the processor
|
2013-12-17 18:10:02 +01:00
|
|
|
*/
|
2014-05-21 15:52:05 +02:00
|
|
|
Processor(unsigned const id, Processor_client * const idle_client,
|
|
|
|
Timer * const timer)
|
2014-03-06 13:55:56 +01:00
|
|
|
:
|
2014-05-21 15:52:05 +02:00
|
|
|
_id(id), _scheduler(idle_client), _ip_interrupt_pending(false),
|
|
|
|
_timer(timer)
|
2014-03-06 13:55:56 +01:00
|
|
|
{ }
|
2013-12-17 18:10:02 +01:00
|
|
|
|
2014-05-21 15:52:05 +02:00
|
|
|
/**
|
|
|
|
* Initializate on the processor that this object corresponds to
|
|
|
|
*/
|
|
|
|
void init_processor_local() { _reset_timer(); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check for a scheduling timeout and handle it in case
|
|
|
|
*
|
|
|
|
* \param interrupt_id kernel name of interrupt that caused this call
|
|
|
|
*
|
|
|
|
* \return wether it was a timeout and therefore has been handled
|
|
|
|
*/
|
|
|
|
bool check_timer_interrupt(unsigned const interrupt_id)
|
|
|
|
{
|
|
|
|
if (_timer->interrupt_id(_id) != interrupt_id) { return false; }
|
|
|
|
_scheduler.yield_occupation();
|
|
|
|
_timer->clear_interrupt(_id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-28 21:31:57 +02:00
|
|
|
/**
|
2014-05-02 18:14:51 +02:00
|
|
|
* Notice that the inter-processor interrupt isn't pending anymore
|
2014-04-28 21:31:57 +02:00
|
|
|
*/
|
2014-05-02 18:14:51 +02:00
|
|
|
void ip_interrupt_handled() { _ip_interrupt_pending = false; }
|
2014-04-28 21:31:57 +02:00
|
|
|
|
2014-03-11 12:53:42 +01:00
|
|
|
/**
|
2014-05-02 18:14:51 +02:00
|
|
|
* Raise the inter-processor interrupt of the processor
|
2014-03-11 12:53:42 +01:00
|
|
|
*/
|
2014-05-02 18:14:51 +02:00
|
|
|
void trigger_ip_interrupt();
|
2014-03-11 12:53:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a processor client to the scheduling plan of the processor
|
|
|
|
*
|
|
|
|
* \param client targeted client
|
|
|
|
*/
|
|
|
|
void schedule(Processor_client * const client);
|
|
|
|
|
2014-05-21 15:52:05 +02:00
|
|
|
/**
|
|
|
|
* Handle exception of the processor and proceed its user execution
|
|
|
|
*/
|
|
|
|
void exception()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Request the current occupant without any update. While the
|
|
|
|
* processor was outside the kernel, another processor may have changed the
|
|
|
|
* scheduling of the local activities in a way that an update would return
|
|
|
|
* an occupant other than that whose exception caused the kernel entry.
|
|
|
|
*/
|
|
|
|
Processor_client * const old_client = _scheduler.occupant();
|
|
|
|
Processor_lazy_state * const old_state = old_client->lazy_state();
|
|
|
|
old_client->exception(_id);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The processor local as well as remote exception-handling may have
|
|
|
|
* changed the scheduling of the local activities. Hence we must update the
|
|
|
|
* occupant.
|
|
|
|
*/
|
|
|
|
bool update;
|
|
|
|
Processor_client * const new_client = _scheduler.update_occupant(update);
|
|
|
|
if (update) { _reset_timer(); }
|
|
|
|
Processor_lazy_state * const new_state = new_client->lazy_state();
|
|
|
|
prepare_proceeding(old_state, new_state);
|
|
|
|
new_client->proceed(_id);
|
|
|
|
}
|
2013-12-17 18:10:02 +01:00
|
|
|
|
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
|
|
|
|
2014-03-06 13:55:56 +01:00
|
|
|
unsigned id() const { return _id; }
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
Processor_scheduler * scheduler() { return &_scheduler; }
|
|
|
|
};
|
|
|
|
|
2014-03-03 15:29:05 +01:00
|
|
|
#endif /* _KERNEL__PROCESSOR_H_ */
|