mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +00:00
parent
d0eaca9915
commit
0d803266ea
@ -532,7 +532,7 @@ void Kernel::Thread::handle_exception()
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::scheduled_next()
|
||||
void Kernel::Thread::proceed()
|
||||
{
|
||||
_mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
|
||||
mtc()->virt_user_entry();
|
||||
@ -747,7 +747,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void scheduled_next()
|
||||
void proceed()
|
||||
{
|
||||
/* set context pointer for mode switch */
|
||||
_mt_client_context_ptr = (addr_t)_state;
|
||||
@ -785,9 +785,7 @@ namespace Kernel
|
||||
initial = 0;
|
||||
}
|
||||
/* create scheduler with a permanent idle thread */
|
||||
static unsigned const user_time_slice =
|
||||
timer()->ms_to_tics(USER_TIME_SLICE_MS);
|
||||
static Cpu_scheduler cpu_sched(&idle, user_time_slice);
|
||||
static Cpu_scheduler cpu_sched(&idle);
|
||||
return &cpu_sched;
|
||||
}
|
||||
|
||||
@ -827,8 +825,9 @@ namespace Kernel
|
||||
|
||||
case Timer::IRQ: {
|
||||
|
||||
/* clear interrupt at timer */
|
||||
cpu_scheduler()->yield();
|
||||
timer()->clear_interrupt();
|
||||
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
||||
break; }
|
||||
|
||||
default: {
|
||||
@ -1439,18 +1438,13 @@ extern "C" void init_phys_kernel() {
|
||||
*/
|
||||
extern "C" void kernel()
|
||||
{
|
||||
static unsigned user_time = 0;
|
||||
static bool initial_call = true;
|
||||
|
||||
/* an exception occured */
|
||||
if (!initial_call)
|
||||
{
|
||||
/* update how much time the last user has consumed */
|
||||
unsigned const timer_value = timer()->stop_one_shot();
|
||||
user_time = timer_value < user_time ? user_time - timer_value : 0;
|
||||
|
||||
/* handle exception that interrupted the last user */
|
||||
cpu_scheduler()->current_entry()->handle_exception();
|
||||
cpu_scheduler()->head()->handle_exception();
|
||||
|
||||
/* kernel initialization */
|
||||
} else {
|
||||
@ -1495,16 +1489,11 @@ extern "C" void kernel()
|
||||
0, core_id(), &cm_utcb, &cm_utcb);
|
||||
|
||||
/* kernel initialization finished */
|
||||
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
||||
initial_call = false;
|
||||
}
|
||||
/* offer next user context to the mode transition PIC */
|
||||
Schedule_context * const next = cpu_scheduler()->next_entry(user_time);
|
||||
|
||||
/* limit user mode execution in time */
|
||||
timer()->start_one_shot(user_time);
|
||||
|
||||
/* will jump to the context related mode-switch */
|
||||
next->scheduled_next();
|
||||
cpu_scheduler()->head()->proceed();
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,7 +49,7 @@ namespace Kernel
|
||||
/* kernel configuration */
|
||||
enum {
|
||||
DEFAULT_STACK_SIZE = 1*1024*1024,
|
||||
USER_TIME_SLICE_MS = 100,
|
||||
USER_LAP_TIME_MS = 100,
|
||||
MAX_PDS = 256,
|
||||
MAX_THREADS = 256,
|
||||
MAX_SIGNAL_RECEIVERS = 256,
|
||||
@ -412,102 +412,50 @@ namespace Kernel
|
||||
public:
|
||||
|
||||
/**
|
||||
* Base class for 'ENTRY_T' to support scheduling
|
||||
* Provides schedulability through inheritance
|
||||
*/
|
||||
class Entry : public Double_list<ENTRY_T>::Entry
|
||||
{
|
||||
friend class Scheduler<ENTRY_T>;
|
||||
|
||||
unsigned _time; /* time wich remains for current lap */
|
||||
|
||||
/**
|
||||
* Apply consumption of 'time'
|
||||
*/
|
||||
void _consume(unsigned const time)
|
||||
{ _time = _time > time ? _time - time : 0; }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Entry() : _time(0) { }
|
||||
};
|
||||
class Entry : public Double_list<ENTRY_T>::Entry { };
|
||||
|
||||
protected:
|
||||
|
||||
ENTRY_T * const _idle; /* Default entry, can't be removed */
|
||||
Double_list<ENTRY_T> _entries; /* List of entries beside '_idle' */
|
||||
unsigned const _lap_time; /* Time that an entry gets for one
|
||||
* scheduling lap to consume */
|
||||
/* gets scheduled when '_entries' is empty */
|
||||
ENTRY_T * const _idle;
|
||||
|
||||
/* scheduling participants beside '_idle' */
|
||||
Double_list<ENTRY_T> _entries;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Scheduler(ENTRY_T * const idle, unsigned const lap_time)
|
||||
: _idle(idle), _lap_time(lap_time) { assert(_lap_time && _idle); }
|
||||
Scheduler(ENTRY_T * const idle)
|
||||
: _idle(idle) { assert(_idle); }
|
||||
|
||||
/**
|
||||
* Returns the entry wich shall scheduled next
|
||||
*
|
||||
* \param t At the call it contains the time, wich was consumed
|
||||
* by the last entry. At the return it is updated to
|
||||
* the next timeslice.
|
||||
* Get currently scheduled entry
|
||||
*/
|
||||
ENTRY_T * next_entry(unsigned & t)
|
||||
{
|
||||
/* update current entry */
|
||||
ENTRY_T * e = _entries.head();
|
||||
if (!e) {
|
||||
t = _lap_time;
|
||||
return _idle;
|
||||
}
|
||||
e->Entry::_consume(t);
|
||||
|
||||
/* lookup entry with time > 0, refresh depleted timeslices */
|
||||
while (!e->Entry::_time) {
|
||||
e->Entry::_time = _lap_time;
|
||||
_entries.head_to_tail();
|
||||
e = _entries.head();
|
||||
}
|
||||
|
||||
/* return next entry and appropriate portion of time */
|
||||
t = e->Entry::_time;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently scheduled entry
|
||||
*/
|
||||
ENTRY_T * current_entry() const {
|
||||
ENTRY_T * head() const {
|
||||
return _entries.head() ? _entries.head() : _idle; }
|
||||
|
||||
/**
|
||||
* Ensure that 'e' does participate in scheduling afterwards
|
||||
* End turn of currently scheduled entry
|
||||
*/
|
||||
void yield() { _entries.head_to_tail(); }
|
||||
|
||||
/**
|
||||
* Include 'e' in scheduling
|
||||
*/
|
||||
void insert(ENTRY_T * const e)
|
||||
{
|
||||
if (e == _idle) return;
|
||||
e->Entry::_time = _lap_time;
|
||||
_entries.insert_tail(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that 'e' doesn't participate in scheduling afterwards
|
||||
* Exclude 'e' from scheduling
|
||||
*/
|
||||
void remove(ENTRY_T * const e) { _entries.remove(e); }
|
||||
|
||||
/**
|
||||
* Set remaining time of currently scheduled entry to 0
|
||||
*/
|
||||
void yield()
|
||||
{
|
||||
ENTRY_T * const e = _entries.head();
|
||||
if (e) e->_time = 0;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
class Schedule_context;
|
||||
@ -521,7 +469,7 @@ namespace Kernel
|
||||
public:
|
||||
|
||||
virtual void handle_exception() = 0;
|
||||
virtual void scheduled_next() = 0;
|
||||
virtual void proceed() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -942,7 +890,7 @@ namespace Kernel
|
||||
/**
|
||||
* Continue executing this thread in userland
|
||||
*/
|
||||
void scheduled_next();
|
||||
void proceed();
|
||||
|
||||
void kill_signal_context_blocks();
|
||||
|
||||
|
@ -61,11 +61,6 @@ class Kernel::Timer : public Genode::Mmio
|
||||
return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms;
|
||||
}
|
||||
|
||||
unsigned stop_one_shot()
|
||||
{
|
||||
return read<Clo>();
|
||||
}
|
||||
|
||||
void clear_interrupt()
|
||||
{
|
||||
write<Cs::Status>(1);
|
||||
|
@ -34,31 +34,13 @@ namespace Cortex_a9
|
||||
*/
|
||||
struct Load : Register<0x0, 32> { };
|
||||
|
||||
/**
|
||||
* Timer counter value register
|
||||
*/
|
||||
struct Counter : Register<0x4, 32> { };
|
||||
|
||||
/**
|
||||
* Timer control register
|
||||
*/
|
||||
struct Control : Register<0x8, 32>
|
||||
{
|
||||
struct Timer_enable : Bitfield<0,1> { }; /* enable counting */
|
||||
struct Auto_reload : Bitfield<1,1> { }; /* reload at zero */
|
||||
struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */
|
||||
struct Prescaler : Bitfield<8,8> { }; /* modify frequency */
|
||||
|
||||
/**
|
||||
* Configure for a one-shot
|
||||
*/
|
||||
static access_t init_one_shot()
|
||||
{
|
||||
return Timer_enable::bits(0) |
|
||||
Auto_reload::bits(0) |
|
||||
Irq_enable::bits(1) |
|
||||
Prescaler::bits(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -69,11 +51,6 @@ namespace Cortex_a9
|
||||
struct Event : Bitfield<0,1> { }; /* if counter hit zero */
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop counting
|
||||
*/
|
||||
void _disable() { write<Control::Timer_enable>(0); }
|
||||
|
||||
public:
|
||||
|
||||
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
|
||||
@ -83,20 +60,20 @@ namespace Cortex_a9
|
||||
*/
|
||||
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
|
||||
{
|
||||
_disable();
|
||||
write<Control::Timer_enable>(0);
|
||||
clear_interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a one-shot run
|
||||
* \param tics native timer value used to assess the delay
|
||||
* of the timer interrupt as of the call
|
||||
* Start one-shot run with an IRQ delay of 'tics'
|
||||
*/
|
||||
inline void start_one_shot(uint32_t const tics)
|
||||
{
|
||||
/* reset timer */
|
||||
clear_interrupt();
|
||||
write<Control>(Control::init_one_shot());
|
||||
Control::access_t control = 0;
|
||||
Control::Irq_enable::set(control, 1);
|
||||
write<Control>(control);
|
||||
|
||||
/* load timer and start decrementing */
|
||||
write<Load>(tics);
|
||||
@ -104,26 +81,20 @@ namespace Cortex_a9
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate milliseconds to a native timer value
|
||||
* Translate 'ms' milliseconds to a native timer value
|
||||
*/
|
||||
static uint32_t ms_to_tics(unsigned const ms) {
|
||||
return ms * TICS_PER_MS; }
|
||||
|
||||
/**
|
||||
* Stop the timer and return last timer value
|
||||
*/
|
||||
unsigned stop_one_shot()
|
||||
static uint32_t ms_to_tics(unsigned const ms)
|
||||
{
|
||||
unsigned const v = read<Counter>();
|
||||
_disable();
|
||||
return v;
|
||||
return ms * TICS_PER_MS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear interrupt output line
|
||||
*/
|
||||
void clear_interrupt() {
|
||||
write<Interrupt_status::Event>(1); }
|
||||
void clear_interrupt()
|
||||
{
|
||||
write<Interrupt_status::Event>(1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,19 +38,6 @@ namespace Exynos_mct
|
||||
{
|
||||
struct Prescaler : Bitfield<0, 8> { };
|
||||
struct Div_mux : Bitfield<8, 3> { };
|
||||
struct Tick_mon_sel : Bitfield<11, 2> { };
|
||||
struct Int_mon_sel : Bitfield<13, 3> { };
|
||||
|
||||
/**
|
||||
* Initialization value
|
||||
*/
|
||||
static access_t init_value()
|
||||
{
|
||||
return Prescaler::bits(PRESCALER) |
|
||||
Div_mux::bits(DIV_MUX) |
|
||||
Tick_mon_sel::bits(0) |
|
||||
Int_mon_sel::bits(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -58,36 +45,35 @@ namespace Exynos_mct
|
||||
*/
|
||||
struct L0_frcntb : Register<0x310, 32> { };
|
||||
|
||||
/**
|
||||
* Local timer 0 free running counter observation
|
||||
*/
|
||||
struct L0_frcnto : Register<0x314, 32> { };
|
||||
|
||||
/**
|
||||
* Local timer 0 configuration
|
||||
*/
|
||||
struct L0_tcon : Register<0x320, 32> {
|
||||
struct L0_tcon : Register<0x320, 32>
|
||||
{
|
||||
struct Frc_start : Bitfield<3, 1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Local timer 0 expired status
|
||||
*/
|
||||
struct L0_int_cstat : Register<0x330, 32, true> {
|
||||
struct L0_int_cstat : Register<0x330, 32, true>
|
||||
{
|
||||
struct Frcnt : Bitfield<1, 1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Local timer 0 interrupt enable
|
||||
*/
|
||||
struct L0_int_enb : Register<0x334, 32> {
|
||||
struct L0_int_enb : Register<0x334, 32>
|
||||
{
|
||||
struct Frceie : Bitfield<1, 1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Local timer 0 write status
|
||||
*/
|
||||
struct L0_wstat : Register<0x340, 32, true> {
|
||||
struct L0_wstat : Register<0x340, 32, true>
|
||||
{
|
||||
struct Frcntb : Bitfield<2, 1> { };
|
||||
struct Tcon : Bitfield<3, 1> { };
|
||||
};
|
||||
@ -110,9 +96,11 @@ namespace Exynos_mct
|
||||
/**
|
||||
* Start and stop counting
|
||||
*/
|
||||
void _run(bool const run) {
|
||||
void _run(bool const run)
|
||||
{
|
||||
_acked_write<L0_tcon, L0_wstat::Tcon>
|
||||
(L0_tcon::Frc_start::bits(run)); }
|
||||
(L0_tcon::Frc_start::bits(run));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -122,15 +110,15 @@ namespace Exynos_mct
|
||||
Timer(addr_t const base, unsigned const clk)
|
||||
: Mmio(base), _tics_per_ms((float)clk / (PRESCALER + 1) / (1 << DIV_MUX) / 1000)
|
||||
{
|
||||
write<Mct_cfg>(Mct_cfg::init_value());
|
||||
Mct_cfg::access_t mct_cfg = 0;
|
||||
Mct_cfg::Prescaler::set(mct_cfg, PRESCALER);
|
||||
Mct_cfg::Div_mux::set(mct_cfg, DIV_MUX);
|
||||
write<Mct_cfg>(mct_cfg);
|
||||
write<L0_int_enb>(L0_int_enb::Frceie::bits(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a one-shot run
|
||||
*
|
||||
* \param tics native timer value used to assess the delay
|
||||
* of the timer interrupt as of the call
|
||||
* Start one-shot run with an IRQ delay of 'tics'
|
||||
*/
|
||||
inline void start_one_shot(unsigned const tics)
|
||||
{
|
||||
@ -140,15 +128,12 @@ namespace Exynos_mct
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate milliseconds to a native timer value
|
||||
* Translate 'ms' milliseconds to a native timer value
|
||||
*/
|
||||
unsigned ms_to_tics(unsigned const ms) {
|
||||
return ms * _tics_per_ms; }
|
||||
|
||||
/**
|
||||
* Stop the timer and return last timer value
|
||||
*/
|
||||
unsigned stop_one_shot() { return read<L0_frcnto>(); }
|
||||
unsigned ms_to_tics(unsigned const ms)
|
||||
{
|
||||
return ms * _tics_per_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear interrupt output line
|
||||
|
Loading…
Reference in New Issue
Block a user