mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 07:46:42 +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);
|
_mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
|
||||||
mtc()->virt_user_entry();
|
mtc()->virt_user_entry();
|
||||||
@ -747,7 +747,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scheduled_next()
|
void proceed()
|
||||||
{
|
{
|
||||||
/* set context pointer for mode switch */
|
/* set context pointer for mode switch */
|
||||||
_mt_client_context_ptr = (addr_t)_state;
|
_mt_client_context_ptr = (addr_t)_state;
|
||||||
@ -785,9 +785,7 @@ namespace Kernel
|
|||||||
initial = 0;
|
initial = 0;
|
||||||
}
|
}
|
||||||
/* create scheduler with a permanent idle thread */
|
/* create scheduler with a permanent idle thread */
|
||||||
static unsigned const user_time_slice =
|
static Cpu_scheduler cpu_sched(&idle);
|
||||||
timer()->ms_to_tics(USER_TIME_SLICE_MS);
|
|
||||||
static Cpu_scheduler cpu_sched(&idle, user_time_slice);
|
|
||||||
return &cpu_sched;
|
return &cpu_sched;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,8 +825,9 @@ namespace Kernel
|
|||||||
|
|
||||||
case Timer::IRQ: {
|
case Timer::IRQ: {
|
||||||
|
|
||||||
/* clear interrupt at timer */
|
cpu_scheduler()->yield();
|
||||||
timer()->clear_interrupt();
|
timer()->clear_interrupt();
|
||||||
|
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
||||||
break; }
|
break; }
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@ -1439,18 +1438,13 @@ extern "C" void init_phys_kernel() {
|
|||||||
*/
|
*/
|
||||||
extern "C" void kernel()
|
extern "C" void kernel()
|
||||||
{
|
{
|
||||||
static unsigned user_time = 0;
|
|
||||||
static bool initial_call = true;
|
static bool initial_call = true;
|
||||||
|
|
||||||
/* an exception occured */
|
/* an exception occured */
|
||||||
if (!initial_call)
|
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 */
|
/* handle exception that interrupted the last user */
|
||||||
cpu_scheduler()->current_entry()->handle_exception();
|
cpu_scheduler()->head()->handle_exception();
|
||||||
|
|
||||||
/* kernel initialization */
|
/* kernel initialization */
|
||||||
} else {
|
} else {
|
||||||
@ -1495,16 +1489,11 @@ extern "C" void kernel()
|
|||||||
0, core_id(), &cm_utcb, &cm_utcb);
|
0, core_id(), &cm_utcb, &cm_utcb);
|
||||||
|
|
||||||
/* kernel initialization finished */
|
/* kernel initialization finished */
|
||||||
|
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
||||||
initial_call = false;
|
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 */
|
/* will jump to the context related mode-switch */
|
||||||
next->scheduled_next();
|
cpu_scheduler()->head()->proceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace Kernel
|
|||||||
/* kernel configuration */
|
/* kernel configuration */
|
||||||
enum {
|
enum {
|
||||||
DEFAULT_STACK_SIZE = 1*1024*1024,
|
DEFAULT_STACK_SIZE = 1*1024*1024,
|
||||||
USER_TIME_SLICE_MS = 100,
|
USER_LAP_TIME_MS = 100,
|
||||||
MAX_PDS = 256,
|
MAX_PDS = 256,
|
||||||
MAX_THREADS = 256,
|
MAX_THREADS = 256,
|
||||||
MAX_SIGNAL_RECEIVERS = 256,
|
MAX_SIGNAL_RECEIVERS = 256,
|
||||||
@ -412,102 +412,50 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for 'ENTRY_T' to support scheduling
|
* Provides schedulability through inheritance
|
||||||
*/
|
*/
|
||||||
class Entry : public Double_list<ENTRY_T>::Entry
|
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) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
ENTRY_T * const _idle; /* Default entry, can't be removed */
|
/* gets scheduled when '_entries' is empty */
|
||||||
Double_list<ENTRY_T> _entries; /* List of entries beside '_idle' */
|
ENTRY_T * const _idle;
|
||||||
unsigned const _lap_time; /* Time that an entry gets for one
|
|
||||||
* scheduling lap to consume */
|
/* scheduling participants beside '_idle' */
|
||||||
|
Double_list<ENTRY_T> _entries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Scheduler(ENTRY_T * const idle, unsigned const lap_time)
|
Scheduler(ENTRY_T * const idle)
|
||||||
: _idle(idle), _lap_time(lap_time) { assert(_lap_time && _idle); }
|
: _idle(idle) { assert(_idle); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the entry wich shall scheduled next
|
* Get currently scheduled entry
|
||||||
*
|
|
||||||
* \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.
|
|
||||||
*/
|
*/
|
||||||
ENTRY_T * next_entry(unsigned & t)
|
ENTRY_T * head() const {
|
||||||
{
|
|
||||||
/* 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 {
|
|
||||||
return _entries.head() ? _entries.head() : _idle; }
|
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)
|
void insert(ENTRY_T * const e)
|
||||||
{
|
{
|
||||||
if (e == _idle) return;
|
if (e == _idle) return;
|
||||||
e->Entry::_time = _lap_time;
|
|
||||||
_entries.insert_tail(e);
|
_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); }
|
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;
|
class Schedule_context;
|
||||||
@ -521,7 +469,7 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void handle_exception() = 0;
|
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
|
* Continue executing this thread in userland
|
||||||
*/
|
*/
|
||||||
void scheduled_next();
|
void proceed();
|
||||||
|
|
||||||
void kill_signal_context_blocks();
|
void kill_signal_context_blocks();
|
||||||
|
|
||||||
|
@ -61,11 +61,6 @@ class Kernel::Timer : public Genode::Mmio
|
|||||||
return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms;
|
return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned stop_one_shot()
|
|
||||||
{
|
|
||||||
return read<Clo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_interrupt()
|
void clear_interrupt()
|
||||||
{
|
{
|
||||||
write<Cs::Status>(1);
|
write<Cs::Status>(1);
|
||||||
|
@ -34,31 +34,13 @@ namespace Cortex_a9
|
|||||||
*/
|
*/
|
||||||
struct Load : Register<0x0, 32> { };
|
struct Load : Register<0x0, 32> { };
|
||||||
|
|
||||||
/**
|
|
||||||
* Timer counter value register
|
|
||||||
*/
|
|
||||||
struct Counter : Register<0x4, 32> { };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timer control register
|
* Timer control register
|
||||||
*/
|
*/
|
||||||
struct Control : Register<0x8, 32>
|
struct Control : Register<0x8, 32>
|
||||||
{
|
{
|
||||||
struct Timer_enable : Bitfield<0,1> { }; /* enable counting */
|
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 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 */
|
struct Event : Bitfield<0,1> { }; /* if counter hit zero */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop counting
|
|
||||||
*/
|
|
||||||
void _disable() { write<Control::Timer_enable>(0); }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
|
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
|
||||||
@ -83,20 +60,20 @@ namespace Cortex_a9
|
|||||||
*/
|
*/
|
||||||
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
|
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
|
||||||
{
|
{
|
||||||
_disable();
|
write<Control::Timer_enable>(0);
|
||||||
clear_interrupt();
|
clear_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a one-shot run
|
* Start one-shot run with an IRQ delay of 'tics'
|
||||||
* \param tics native timer value used to assess the delay
|
|
||||||
* of the timer interrupt as of the call
|
|
||||||
*/
|
*/
|
||||||
inline void start_one_shot(uint32_t const tics)
|
inline void start_one_shot(uint32_t const tics)
|
||||||
{
|
{
|
||||||
/* reset timer */
|
/* reset timer */
|
||||||
clear_interrupt();
|
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 */
|
/* load timer and start decrementing */
|
||||||
write<Load>(tics);
|
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) {
|
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()
|
|
||||||
{
|
{
|
||||||
unsigned const v = read<Counter>();
|
return ms * TICS_PER_MS;
|
||||||
_disable();
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear interrupt output line
|
* Clear interrupt output line
|
||||||
*/
|
*/
|
||||||
void clear_interrupt() {
|
void clear_interrupt()
|
||||||
write<Interrupt_status::Event>(1); }
|
{
|
||||||
|
write<Interrupt_status::Event>(1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,19 +38,6 @@ namespace Exynos_mct
|
|||||||
{
|
{
|
||||||
struct Prescaler : Bitfield<0, 8> { };
|
struct Prescaler : Bitfield<0, 8> { };
|
||||||
struct Div_mux : Bitfield<8, 3> { };
|
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> { };
|
struct L0_frcntb : Register<0x310, 32> { };
|
||||||
|
|
||||||
/**
|
|
||||||
* Local timer 0 free running counter observation
|
|
||||||
*/
|
|
||||||
struct L0_frcnto : Register<0x314, 32> { };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 configuration
|
* Local timer 0 configuration
|
||||||
*/
|
*/
|
||||||
struct L0_tcon : Register<0x320, 32> {
|
struct L0_tcon : Register<0x320, 32>
|
||||||
|
{
|
||||||
struct Frc_start : Bitfield<3, 1> { };
|
struct Frc_start : Bitfield<3, 1> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 expired status
|
* 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> { };
|
struct Frcnt : Bitfield<1, 1> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 interrupt enable
|
* Local timer 0 interrupt enable
|
||||||
*/
|
*/
|
||||||
struct L0_int_enb : Register<0x334, 32> {
|
struct L0_int_enb : Register<0x334, 32>
|
||||||
|
{
|
||||||
struct Frceie : Bitfield<1, 1> { };
|
struct Frceie : Bitfield<1, 1> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 write status
|
* 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 Frcntb : Bitfield<2, 1> { };
|
||||||
struct Tcon : Bitfield<3, 1> { };
|
struct Tcon : Bitfield<3, 1> { };
|
||||||
};
|
};
|
||||||
@ -110,9 +96,11 @@ namespace Exynos_mct
|
|||||||
/**
|
/**
|
||||||
* Start and stop counting
|
* Start and stop counting
|
||||||
*/
|
*/
|
||||||
void _run(bool const run) {
|
void _run(bool const run)
|
||||||
|
{
|
||||||
_acked_write<L0_tcon, L0_wstat::Tcon>
|
_acked_write<L0_tcon, L0_wstat::Tcon>
|
||||||
(L0_tcon::Frc_start::bits(run)); }
|
(L0_tcon::Frc_start::bits(run));
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -122,15 +110,15 @@ namespace Exynos_mct
|
|||||||
Timer(addr_t const base, unsigned const clk)
|
Timer(addr_t const base, unsigned const clk)
|
||||||
: Mmio(base), _tics_per_ms((float)clk / (PRESCALER + 1) / (1 << DIV_MUX) / 1000)
|
: 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));
|
write<L0_int_enb>(L0_int_enb::Frceie::bits(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a one-shot run
|
* Start one-shot run with an IRQ delay of 'tics'
|
||||||
*
|
|
||||||
* \param tics native timer value used to assess the delay
|
|
||||||
* of the timer interrupt as of the call
|
|
||||||
*/
|
*/
|
||||||
inline void start_one_shot(unsigned const 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) {
|
unsigned ms_to_tics(unsigned const ms)
|
||||||
return ms * _tics_per_ms; }
|
{
|
||||||
|
return ms * _tics_per_ms;
|
||||||
/**
|
}
|
||||||
* Stop the timer and return last timer value
|
|
||||||
*/
|
|
||||||
unsigned stop_one_shot() { return read<L0_frcnto>(); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear interrupt output line
|
* Clear interrupt output line
|
||||||
|
Loading…
Reference in New Issue
Block a user