diff --git a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a15.inc b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a15.inc index 24fcd27a6f..5bd4a7e1a1 100644 --- a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a15.inc +++ b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a15.inc @@ -7,7 +7,7 @@ # add C++ sources SRC_CC += spec/arm/cortex_a15_cpu.cc SRC_CC += kernel/cpu_mp.cc -SRC_CC += spec/arm/kernel/lock.cc +SRC_CC += spec/arm/kernel/mutex.cc # include less specific configuration include $(call select_from_repositories,lib/mk/spec/arm_v7/core-hw.inc) diff --git a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a9.inc b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a9.inc index 72eb114a58..b0ddd3e9a8 100644 --- a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a9.inc +++ b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-cortex_a9.inc @@ -9,7 +9,7 @@ SRC_CC += spec/arm/cortex_a9_board.cc SRC_CC += spec/arm/cortex_a9_cpu.cc SRC_CC += spec/arm/cortex_a9_global_timer.cc SRC_CC += spec/arm/gicv2.cc -SRC_CC += spec/arm/kernel/lock.cc +SRC_CC += spec/arm/kernel/mutex.cc SRC_CC += kernel/vm_thread_off.cc SRC_CC += kernel/cpu_mp.cc diff --git a/repos/base-hw/lib/mk/spec/arm_v8/core-hw.inc b/repos/base-hw/lib/mk/spec/arm_v8/core-hw.inc index df0699a791..cb8f58b217 100644 --- a/repos/base-hw/lib/mk/spec/arm_v8/core-hw.inc +++ b/repos/base-hw/lib/mk/spec/arm_v8/core-hw.inc @@ -10,7 +10,7 @@ LIBS += syscall-hw # add C++ sources SRC_CC += kernel/cpu_mp.cc SRC_CC += spec/arm/generic_timer.cc -SRC_CC += spec/arm/kernel/lock.cc +SRC_CC += spec/arm/kernel/mutex.cc SRC_CC += spec/arm/kernel/thread_caches.cc SRC_CC += spec/arm/platform_support.cc SRC_CC += spec/arm_v8/cpu.cc diff --git a/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk b/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk index ab6f733f84..2a3a507fda 100644 --- a/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk +++ b/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk @@ -18,11 +18,11 @@ SRC_S += spec/x86_64/exception_vector.s # add C++ sources SRC_CC += kernel/cpu_mp.cc +SRC_CC += kernel/mutex.cc SRC_CC += kernel/vm_thread_on.cc SRC_CC += spec/x86_64/virtualization/kernel/vm.cc SRC_CC += spec/x86_64/virtualization/kernel/svm.cc SRC_CC += spec/x86_64/virtualization/kernel/vmx.cc -SRC_CC += kernel/lock.cc SRC_CC += spec/x86_64/pic.cc SRC_CC += spec/x86_64/timer.cc SRC_CC += spec/x86_64/kernel/thread_exception.cc diff --git a/repos/base-hw/src/core/kernel/lock.h b/repos/base-hw/src/core/kernel/lock.h deleted file mode 100644 index 60b542166b..0000000000 --- a/repos/base-hw/src/core/kernel/lock.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * \brief Kernel lock - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-11-30 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__SMP__KERNEL__LOCK_H_ -#define _CORE__SPEC__SMP__KERNEL__LOCK_H_ - -namespace Kernel { class Lock; } - - -class Kernel::Lock -{ - private: - - enum { INVALID = ~0U }; - - enum State { UNLOCKED, LOCKED }; - - int volatile _locked { UNLOCKED }; - unsigned volatile _current_cpu { INVALID }; - - public: - - void lock(); - void unlock(); - - struct Guard - { - Lock &_lock; - - explicit Guard(Lock &lock) : _lock(lock) { _lock.lock(); } - - ~Guard() { _lock.unlock(); } - }; -}; - -#endif /* _CORE__SPEC__SMP__KERNEL__LOCK_H_ */ diff --git a/repos/base-hw/src/core/kernel/main.cc b/repos/base-hw/src/core/kernel/main.cc index a66f1405ce..f8fc2cf7d2 100644 --- a/repos/base-hw/src/core/kernel/main.cc +++ b/repos/base-hw/src/core/kernel/main.cc @@ -15,7 +15,7 @@ /* core includes */ #include #include -#include +#include #include #include #include @@ -39,7 +39,7 @@ class Kernel::Main static Main *_instance; - Lock _data_lock { }; + Mutex _mutex { }; Cpu_pool _cpu_pool { }; Irq::Pool _user_irq_pool { }; Board::Address_space_id_allocator _addr_space_id_alloc { }; @@ -65,12 +65,14 @@ void Kernel::Main::_handle_kernel_entry() { Cpu::Context * context; - { - Lock::Guard guard(_data_lock); - - context = - &_cpu_pool.cpu(Cpu::executing_id()).handle_exception_and_schedule(); - } + _mutex.execute_exclusive( + [&] () { + Cpu &cpu = _cpu_pool.cpu(Cpu::executing_id()); + context = &cpu.handle_exception_and_schedule(); + }, + [&] () { + Genode::error("Cpu ", Cpu::executing_id(), " re-entered lock.", + "Kernel exception?!"); }); context->proceed(); } @@ -86,7 +88,7 @@ void Kernel::main_initialize_and_handle_kernel_entry() { using Boot_info = Hw::Boot_info; - static Lock init_lock; + static Mutex init_mutex; static volatile unsigned nr_of_initialized_cpus { 0 }; static volatile bool kernel_initialized { false }; @@ -99,35 +101,34 @@ void Kernel::main_initialize_and_handle_kernel_entry() * Let the first CPU create a Main object and initialize the static * reference to it. */ - { - Lock::Guard guard(init_lock); - - static Main instance; - Main::_instance = &instance; - - } + init_mutex.execute_exclusive( + [&] () { + static Main instance; + Main::_instance = &instance; }, + [&] () { + Genode::error("recursive call of ", __func__); }); /* the CPU resumed if the kernel is already initialized */ if (kernel_initialized) { - { - Lock::Guard guard(Main::_instance->_data_lock); + Main::_instance->_mutex.execute_exclusive( + [&] () { + if (nr_of_initialized_cpus == nr_of_cpus) { + nr_of_initialized_cpus = 0; - if (nr_of_initialized_cpus == nr_of_cpus) { - nr_of_initialized_cpus = 0; + Main::_instance->_serial.init(); + Main::_instance->_global_irq_ctrl.init(); + } - Main::_instance->_serial.init(); - Main::_instance->_global_irq_ctrl.init(); - } + nr_of_initialized_cpus = nr_of_initialized_cpus + 1; - nr_of_initialized_cpus = nr_of_initialized_cpus + 1; + Main::_instance->_cpu_pool.cpu(Cpu::executing_id()).reinit_cpu(); - Main::_instance->_cpu_pool.cpu(Cpu::executing_id()).reinit_cpu(); - - if (nr_of_initialized_cpus == nr_of_cpus) { - Genode::raw("kernel resumed"); - } - } + if (nr_of_initialized_cpus == nr_of_cpus) + Genode::raw("kernel resumed"); + }, + [&] () { + Genode::error("recursive call of ", __func__); }); while (nr_of_initialized_cpus < nr_of_cpus) { } @@ -136,20 +137,21 @@ void Kernel::main_initialize_and_handle_kernel_entry() return; } - { - /** - * Let each CPU initialize its corresponding CPU object in the - * CPU pool. - */ - Lock::Guard guard(Main::_instance->_data_lock); - Main::_instance->_cpu_pool.initialize_executing_cpu( - Main::_instance->_addr_space_id_alloc, - Main::_instance->_user_irq_pool, - Main::_instance->_core_platform_pd.kernel_pd(), - Main::_instance->_global_irq_ctrl); + Main::_instance->_mutex.execute_exclusive( + [&] () { + /** + * Let each CPU initialize its corresponding CPU object in the + * CPU pool. + */ + Main::_instance->_cpu_pool.initialize_executing_cpu( + Main::_instance->_addr_space_id_alloc, + Main::_instance->_user_irq_pool, + Main::_instance->_core_platform_pd.kernel_pd(), + Main::_instance->_global_irq_ctrl); - nr_of_initialized_cpus = nr_of_initialized_cpus + 1; - }; + nr_of_initialized_cpus = nr_of_initialized_cpus + 1; }, + [&] () { + Genode::error("recursive call of ", __func__); }); /** * Let all CPUs block until each CPU object in the CPU pool has been @@ -161,29 +163,30 @@ void Kernel::main_initialize_and_handle_kernel_entry() * Let the primary CPU initialize the core main thread and finish * initialization of the boot info. */ - { - Lock::Guard guard(Main::_instance->_data_lock); + Main::_instance->_mutex.execute_exclusive( + [&] () { + if (Cpu::executing_id() == Main::_instance->_cpu_pool.primary_cpu().id()) { + Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) { + boot_info.kernel_irqs.add(cpu.timer().interrupt_id()); + }); + boot_info.kernel_irqs.add((unsigned)Board::Pic::IPI); - if (Cpu::executing_id() == Main::_instance->_cpu_pool.primary_cpu().id()) { - Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) { - boot_info.kernel_irqs.add(cpu.timer().interrupt_id()); - }); - boot_info.kernel_irqs.add((unsigned)Board::Pic::IPI); + Main::_instance->_core_main_thread.construct( + Main::_instance->_addr_space_id_alloc, + Main::_instance->_user_irq_pool, + Main::_instance->_cpu_pool, + Main::_instance->_core_platform_pd.kernel_pd()); - Main::_instance->_core_main_thread.construct( - Main::_instance->_addr_space_id_alloc, - Main::_instance->_user_irq_pool, - Main::_instance->_cpu_pool, - Main::_instance->_core_platform_pd.kernel_pd()); + boot_info.core_main_thread_utcb = + (addr_t)Main::_instance->_core_main_thread->utcb(); - boot_info.core_main_thread_utcb = - (addr_t)Main::_instance->_core_main_thread->utcb(); - - Genode::log(""); - Genode::log("kernel initialized"); - kernel_initialized = true; - } - } + Genode::log(""); + Genode::log("kernel initialized"); + kernel_initialized = true; + } + }, + [&] () { + Genode::error("recursive call of ", __func__); }); /** * Let secondary CPUs block until the primary CPU has initialized the diff --git a/repos/base-hw/src/core/kernel/lock.cc b/repos/base-hw/src/core/kernel/mutex.cc similarity index 53% rename from repos/base-hw/src/core/kernel/lock.cc rename to repos/base-hw/src/core/kernel/mutex.cc index e5b199dec6..ad33a9b837 100644 --- a/repos/base-hw/src/core/kernel/lock.cc +++ b/repos/base-hw/src/core/kernel/mutex.cc @@ -1,11 +1,11 @@ /* - * \brief Kernel lock for multi-processor systems + * \brief Kernel mutex * \author Stefan Kalkowski - * \date 2018-11-20 + * \date 2024-11-22 */ /* - * Copyright (C) 2019 Genode Labs GmbH + * Copyright (C) 2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -17,25 +17,21 @@ /* base-hw core includes */ #include -#include +#include -void Kernel::Lock::lock() +bool Kernel::Mutex::_lock() { - /* check for the lock holder being the same cpu */ - if (_current_cpu == Cpu::executing_id()) { - /* at least print an error message */ - Genode::raw("Cpu ", _current_cpu, - " error: re-entered lock. Kernel exception?!"); - } - - while (!Genode::cmpxchg((volatile int*)&_locked, UNLOCKED, LOCKED)) { ; } + while (!Genode::cmpxchg((volatile int*)&_locked, UNLOCKED, LOCKED)) + if (_current_cpu == Cpu::executing_id()) + return false; _current_cpu = Cpu::executing_id(); + return true; } -void Kernel::Lock::unlock() +void Kernel::Mutex::_unlock() { _current_cpu = INVALID; diff --git a/repos/base-hw/src/core/kernel/mutex.h b/repos/base-hw/src/core/kernel/mutex.h new file mode 100644 index 0000000000..12a7bef7a4 --- /dev/null +++ b/repos/base-hw/src/core/kernel/mutex.h @@ -0,0 +1,62 @@ +/* + * \brief Kernel mutex + * \author Stefan Kalkowski + * \date 2024-11-22 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__KERNEL__MUTEX_H_ +#define _CORE__KERNEL__MUTEX_H_ + +namespace Kernel { class Mutex; } + + +class Kernel::Mutex +{ + private: + + enum { INVALID = ~0U }; + + enum State { UNLOCKED, LOCKED }; + + State volatile _locked { UNLOCKED }; + unsigned volatile _current_cpu { INVALID }; + + bool _lock(); + void _unlock(); + + public: + + /** + * Execute exclusively some critical section with lambda 'fn', + * if the critical section is called recursively by the same cpu + * lambda 'reentered' is called instead. + */ + void execute_exclusive(auto const &fn, + auto const &reentered) + { + /* + * If the lock cannot get acquired, it is already taken by this cpu. + * That means implicitely that most probably some machine exception + * during kernel execution forced the cpu to re-enter this critical + * section. + */ + if (!_lock()) { + reentered(); + + /* block forever */ + while (!_lock()) ; + } + + fn(); + _unlock(); + } +}; + +#endif /* _CORE__KERNEL__MUTEX_H_ */ diff --git a/repos/base-hw/src/core/platform_pd.h b/repos/base-hw/src/core/platform_pd.h index c40187a4bc..f7e6ef88f1 100644 --- a/repos/base-hw/src/core/platform_pd.h +++ b/repos/base-hw/src/core/platform_pd.h @@ -74,7 +74,7 @@ class Hw::Address_space : public Core::Address_space using Table = Hw::Page_table; using Array = Table::Allocator::Array; - Mutex _mutex { }; /* table lock */ + Genode::Mutex _mutex { }; /* table lock */ Table &_tt; /* table virt addr */ addr_t _tt_phys; /* table phys addr */ Array *_tt_array = nullptr; diff --git a/repos/base-hw/src/core/spec/arm/kernel/lock.cc b/repos/base-hw/src/core/spec/arm/kernel/mutex.cc similarity index 52% rename from repos/base-hw/src/core/spec/arm/kernel/lock.cc rename to repos/base-hw/src/core/spec/arm/kernel/mutex.cc index 5815eb209d..f6a94ce249 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/lock.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/mutex.cc @@ -1,11 +1,11 @@ /* - * \brief Kernel lock for multi-processor systems + * \brief Kernel mutex * \author Stefan Kalkowski * \date 2018-11-20 */ /* - * Copyright (C) 2019 Genode Labs GmbH + * Copyright (C) 2019-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -17,24 +17,21 @@ /* base-hw core includes */ #include -#include +#include -void Kernel::Lock::lock() +bool Kernel::Mutex::_lock() { - /* check for the lock holder being the same cpu */ - if (_current_cpu == Cpu::executing_id()) { - /* at least print an error message */ - Genode::raw("Cpu ", _current_cpu, - " error: re-entered lock. Kernel exception?!"); - } + if (_current_cpu == Cpu::executing_id()) + return false; - Cpu::wait_for_xchg(&_locked, LOCKED, UNLOCKED); + Cpu::wait_for_xchg((volatile int*)&_locked, LOCKED, UNLOCKED); _current_cpu = Cpu::executing_id(); + return true; } -void Kernel::Lock::unlock() +void Kernel::Mutex::_unlock() { _current_cpu = INVALID;