From 1b5bfec8f992dcacf4642b5ddc75011f5f781ef2 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 8 Dec 2022 13:47:52 +0100 Subject: [PATCH] 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 --- repos/base-hw/src/core/kernel/cpu.cc | 3 ++ repos/base-hw/src/core/kernel/cpu.h | 30 +++++++++++++++++++ repos/base-hw/src/core/kernel/main.cc | 27 +++++++++++++++++ .../src/core/spec/arm/kernel/thread.cc | 3 ++ .../src/core/spec/arm_v8/kernel/thread.cc | 3 ++ .../src/core/spec/riscv/kernel/thread.cc | 3 ++ .../src/core/spec/x86_64/kernel/thread.cc | 3 ++ 7 files changed, 72 insertions(+) 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() { }