diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index 91609ed1df..0f752a3c98 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -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()); diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h index cb24468270..833af3819d 100644 --- a/repos/base-hw/src/core/kernel/cpu.h +++ b/repos/base-hw/src/core/kernel/cpu.h @@ -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' */ diff --git a/repos/base-hw/src/core/kernel/main.cc b/repos/base-hw/src/core/kernel/main.cc index 855d6dbb7c..f4beb07755 100644 --- a/repos/base-hw/src/core/kernel/main.cc +++ b/repos/base-hw/src/core/kernel/main.cc @@ -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 diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread.cc b/repos/base-hw/src/core/spec/arm/kernel/thread.cc index 48c154ffcc..0a63aac23b 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/thread.cc @@ -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) diff --git a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc index 4879814fd4..34946b1183 100644 --- a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc @@ -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; diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc index 21be01c2b2..6ab3c3004d 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc @@ -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; diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc index 1c1b041196..3ed9b75986 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc @@ -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() { }