hw: add CPU re-init/resume support

On resume the CPU state must be re-initialized, since all CPUs have been
potentially off (depending on sleep form) and lost state. Handle the halt
and suspend state explicitly by an extra Job implementation which can be
executed without holding the global kernel lock.

Issue #4669
This commit is contained in:
Alexander Boettcher 2022-12-08 13:47:52 +01:00 committed by Christian Helmuth
parent a20a26b41b
commit 1b5bfec8f9
7 changed files with 72 additions and 0 deletions

View File

@ -145,6 +145,9 @@ Cpu_job & Cpu::schedule()
Job & old_job = scheduled_job();
old_job.exception(*this);
if (_state == SUSPEND || _state == HALT)
return _halt_job;
if (_scheduler.need_to_schedule()) {
_timer.process_timeouts();
_scheduler.update(_timer.time());

View File

@ -109,7 +109,20 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
Pd &core_pd);
};
struct Halt_job : Job
{
Halt_job() : Job (0, 0) { }
void exception(Kernel::Cpu &) override { }
void proceed(Kernel::Cpu &) override;
Kernel::Cpu_job* helping_destination() override { return this; }
} _halt_job { };
enum State { RUN, HALT, SUSPEND };
State _state { RUN };
unsigned const _id;
Board::Pic _pic;
Timer _timer;
@ -126,6 +139,11 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
public:
void next_state_halt() { _state = HALT; };
void next_state_suspend() { _state = SUSPEND; };
State state() { return _state; }
enum { KERNEL_STACK_SIZE = 16 * 1024 * sizeof(Genode::addr_t) };
/**
@ -186,6 +204,12 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
* Return CPU's idle thread object
*/
Kernel::Thread &idle_thread() { return _idle; }
void reinit_cpu()
{
_arch_init();
_state = RUN;
}
};
@ -213,6 +237,12 @@ class Kernel::Cpu_pool
Pd &core_pd,
Board::Global_interrupt_controller &global_irq_ctrl);
/**
* Return whether CPU object is valid and is constructed.
*/
bool cpu_valid(unsigned const id) const {
return id < _nr_of_cpus && _cpus[id].constructed(); }
/**
* Return object of CPU 'id'
*/

View File

@ -134,6 +134,33 @@ void Kernel::main_initialize_and_handle_kernel_entry()
while (!instance_initialized) { }
}
if (Main::_instance->_cpu_pool.cpu_valid(Cpu::executing_id())) {
/* the CPU resumed since the cpu object is already valid */
{
Lock::Guard guard(Main::_instance->_data_lock);
if (kernel_initialized) {
nr_of_initialized_cpus = 0;
kernel_initialized = false;
}
nr_of_initialized_cpus ++;
Main::_instance->_cpu_pool.cpu(Cpu::executing_id()).reinit_cpu();
if (nr_of_initialized_cpus == nr_of_cpus) {
kernel_initialized = true;
Genode::raw("kernel resumed");
}
}
while (!kernel_initialized) { }
Main::_instance->_handle_kernel_entry();
/* never reached */
return;
}
{
/**
* Let each CPU initialize its corresponding CPU object in the

View File

@ -68,6 +68,9 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { }
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
void Cpu::Halt_job::proceed(Kernel::Cpu &) { }
void Thread::proceed(Cpu & cpu)
{
if (!cpu.active(pd().mmu_regs) && type() != CORE)

View File

@ -88,6 +88,9 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { }
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
void Cpu::Halt_job::proceed(Kernel::Cpu &) { }
bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size)
{
using namespace Genode;

View File

@ -25,6 +25,9 @@ void Thread::Tlb_invalidation::execute(Cpu &) { }
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
void Cpu::Halt_job::proceed(Kernel::Cpu &) { }
void Thread::exception(Cpu & cpu)
{
using Context = Genode::Cpu::Context;

View File

@ -35,6 +35,9 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &)
void Kernel::Thread::Flush_and_stop_cpu::execute(Cpu &) { }
void Kernel::Cpu::Halt_job::proceed(Kernel::Cpu &) { }
void Kernel::Thread::_call_cache_coherent_region() { }