hw: re-implement kernel mutex

* Rename Kernel::Lock into Kernel::Mutex
* Replace Guard object by template function that expects
  lambda to handle re-entrance by same cpu

Ref genodelabs/genode#5425
This commit is contained in:
Stefan Kalkowski 2025-01-24 13:22:12 +01:00 committed by Christian Helmuth
parent c2cee1a885
commit 98032a2605
10 changed files with 152 additions and 141 deletions

View File

@ -7,7 +7,7 @@
# add C++ sources # add C++ sources
SRC_CC += spec/arm/cortex_a15_cpu.cc SRC_CC += spec/arm/cortex_a15_cpu.cc
SRC_CC += kernel/cpu_mp.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 less specific configuration
include $(call select_from_repositories,lib/mk/spec/arm_v7/core-hw.inc) include $(call select_from_repositories,lib/mk/spec/arm_v7/core-hw.inc)

View File

@ -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_cpu.cc
SRC_CC += spec/arm/cortex_a9_global_timer.cc SRC_CC += spec/arm/cortex_a9_global_timer.cc
SRC_CC += spec/arm/gicv2.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/vm_thread_off.cc
SRC_CC += kernel/cpu_mp.cc SRC_CC += kernel/cpu_mp.cc

View File

@ -10,7 +10,7 @@ LIBS += syscall-hw
# add C++ sources # add C++ sources
SRC_CC += kernel/cpu_mp.cc SRC_CC += kernel/cpu_mp.cc
SRC_CC += spec/arm/generic_timer.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/kernel/thread_caches.cc
SRC_CC += spec/arm/platform_support.cc SRC_CC += spec/arm/platform_support.cc
SRC_CC += spec/arm_v8/cpu.cc SRC_CC += spec/arm_v8/cpu.cc

View File

@ -18,11 +18,11 @@ SRC_S += spec/x86_64/exception_vector.s
# add C++ sources # add C++ sources
SRC_CC += kernel/cpu_mp.cc SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/mutex.cc
SRC_CC += kernel/vm_thread_on.cc SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/x86_64/virtualization/kernel/vm.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/svm.cc
SRC_CC += spec/x86_64/virtualization/kernel/vmx.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/pic.cc
SRC_CC += spec/x86_64/timer.cc SRC_CC += spec/x86_64/timer.cc
SRC_CC += spec/x86_64/kernel/thread_exception.cc SRC_CC += spec/x86_64/kernel/thread_exception.cc

View File

@ -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_ */

View File

@ -15,7 +15,7 @@
/* core includes */ /* core includes */
#include <map_local.h> #include <map_local.h>
#include <kernel/cpu.h> #include <kernel/cpu.h>
#include <kernel/lock.h> #include <kernel/mutex.h>
#include <kernel/main.h> #include <kernel/main.h>
#include <platform_pd.h> #include <platform_pd.h>
#include <platform_thread.h> #include <platform_thread.h>
@ -39,7 +39,7 @@ class Kernel::Main
static Main *_instance; static Main *_instance;
Lock _data_lock { }; Mutex _mutex { };
Cpu_pool _cpu_pool { }; Cpu_pool _cpu_pool { };
Irq::Pool _user_irq_pool { }; Irq::Pool _user_irq_pool { };
Board::Address_space_id_allocator _addr_space_id_alloc { }; Board::Address_space_id_allocator _addr_space_id_alloc { };
@ -65,12 +65,14 @@ void Kernel::Main::_handle_kernel_entry()
{ {
Cpu::Context * context; Cpu::Context * context;
{ _mutex.execute_exclusive(
Lock::Guard guard(_data_lock); [&] () {
Cpu &cpu = _cpu_pool.cpu(Cpu::executing_id());
context = context = &cpu.handle_exception_and_schedule();
&_cpu_pool.cpu(Cpu::executing_id()).handle_exception_and_schedule(); },
} [&] () {
Genode::error("Cpu ", Cpu::executing_id(), " re-entered lock.",
"Kernel exception?!"); });
context->proceed(); context->proceed();
} }
@ -86,7 +88,7 @@ void Kernel::main_initialize_and_handle_kernel_entry()
{ {
using Boot_info = Hw::Boot_info<Board::Boot_info>; using Boot_info = Hw::Boot_info<Board::Boot_info>;
static Lock init_lock; static Mutex init_mutex;
static volatile unsigned nr_of_initialized_cpus { 0 }; static volatile unsigned nr_of_initialized_cpus { 0 };
static volatile bool kernel_initialized { false }; static volatile bool kernel_initialized { false };
@ -99,20 +101,18 @@ void Kernel::main_initialize_and_handle_kernel_entry()
* Let the first CPU create a Main object and initialize the static * Let the first CPU create a Main object and initialize the static
* reference to it. * reference to it.
*/ */
{ init_mutex.execute_exclusive(
Lock::Guard guard(init_lock); [&] () {
static Main instance; static Main instance;
Main::_instance = &instance; Main::_instance = &instance; },
[&] () {
} Genode::error("recursive call of ", __func__); });
/* the CPU resumed if the kernel is already initialized */ /* the CPU resumed if the kernel is already initialized */
if (kernel_initialized) { if (kernel_initialized) {
{ Main::_instance->_mutex.execute_exclusive(
Lock::Guard guard(Main::_instance->_data_lock); [&] () {
if (nr_of_initialized_cpus == nr_of_cpus) { if (nr_of_initialized_cpus == nr_of_cpus) {
nr_of_initialized_cpus = 0; nr_of_initialized_cpus = 0;
@ -124,10 +124,11 @@ void Kernel::main_initialize_and_handle_kernel_entry()
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) { if (nr_of_initialized_cpus == nr_of_cpus)
Genode::raw("kernel resumed"); Genode::raw("kernel resumed");
} },
} [&] () {
Genode::error("recursive call of ", __func__); });
while (nr_of_initialized_cpus < nr_of_cpus) { } while (nr_of_initialized_cpus < nr_of_cpus) { }
@ -136,20 +137,21 @@ void Kernel::main_initialize_and_handle_kernel_entry()
return; return;
} }
{ Main::_instance->_mutex.execute_exclusive(
[&] () {
/** /**
* Let each CPU initialize its corresponding CPU object in the * Let each CPU initialize its corresponding CPU object in the
* CPU pool. * CPU pool.
*/ */
Lock::Guard guard(Main::_instance->_data_lock);
Main::_instance->_cpu_pool.initialize_executing_cpu( Main::_instance->_cpu_pool.initialize_executing_cpu(
Main::_instance->_addr_space_id_alloc, Main::_instance->_addr_space_id_alloc,
Main::_instance->_user_irq_pool, Main::_instance->_user_irq_pool,
Main::_instance->_core_platform_pd.kernel_pd(), Main::_instance->_core_platform_pd.kernel_pd(),
Main::_instance->_global_irq_ctrl); 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 * Let all CPUs block until each CPU object in the CPU pool has been
@ -161,9 +163,8 @@ void Kernel::main_initialize_and_handle_kernel_entry()
* Let the primary CPU initialize the core main thread and finish * Let the primary CPU initialize the core main thread and finish
* initialization of the boot info. * initialization of the boot info.
*/ */
{ Main::_instance->_mutex.execute_exclusive(
Lock::Guard guard(Main::_instance->_data_lock); [&] () {
if (Cpu::executing_id() == Main::_instance->_cpu_pool.primary_cpu().id()) { if (Cpu::executing_id() == Main::_instance->_cpu_pool.primary_cpu().id()) {
Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) { Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) {
boot_info.kernel_irqs.add(cpu.timer().interrupt_id()); boot_info.kernel_irqs.add(cpu.timer().interrupt_id());
@ -183,7 +184,9 @@ void Kernel::main_initialize_and_handle_kernel_entry()
Genode::log("kernel initialized"); Genode::log("kernel initialized");
kernel_initialized = true; kernel_initialized = true;
} }
} },
[&] () {
Genode::error("recursive call of ", __func__); });
/** /**
* Let secondary CPUs block until the primary CPU has initialized the * Let secondary CPUs block until the primary CPU has initialized the

View File

@ -1,11 +1,11 @@
/* /*
* \brief Kernel lock for multi-processor systems * \brief Kernel mutex
* \author Stefan Kalkowski * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
@ -17,25 +17,21 @@
/* base-hw core includes */ /* base-hw core includes */
#include <kernel/cpu.h> #include <kernel/cpu.h>
#include <kernel/lock.h> #include <kernel/mutex.h>
void Kernel::Lock::lock() bool Kernel::Mutex::_lock()
{ {
/* check for the lock holder being the same cpu */ while (!Genode::cmpxchg((volatile int*)&_locked, UNLOCKED, LOCKED))
if (_current_cpu == Cpu::executing_id()) { if (_current_cpu == Cpu::executing_id())
/* at least print an error message */ return false;
Genode::raw("Cpu ", _current_cpu,
" error: re-entered lock. Kernel exception?!");
}
while (!Genode::cmpxchg((volatile int*)&_locked, UNLOCKED, LOCKED)) { ; }
_current_cpu = Cpu::executing_id(); _current_cpu = Cpu::executing_id();
return true;
} }
void Kernel::Lock::unlock() void Kernel::Mutex::_unlock()
{ {
_current_cpu = INVALID; _current_cpu = INVALID;

View File

@ -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_ */

View File

@ -74,7 +74,7 @@ class Hw::Address_space : public Core::Address_space
using Table = Hw::Page_table; using Table = Hw::Page_table;
using Array = Table::Allocator::Array<DEFAULT_TRANSLATION_TABLE_MAX>; using Array = Table::Allocator::Array<DEFAULT_TRANSLATION_TABLE_MAX>;
Mutex _mutex { }; /* table lock */ Genode::Mutex _mutex { }; /* table lock */
Table &_tt; /* table virt addr */ Table &_tt; /* table virt addr */
addr_t _tt_phys; /* table phys addr */ addr_t _tt_phys; /* table phys addr */
Array *_tt_array = nullptr; Array *_tt_array = nullptr;

View File

@ -1,11 +1,11 @@
/* /*
* \brief Kernel lock for multi-processor systems * \brief Kernel mutex
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \date 2018-11-20 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
@ -17,24 +17,21 @@
/* base-hw core includes */ /* base-hw core includes */
#include <kernel/cpu.h> #include <kernel/cpu.h>
#include <kernel/lock.h> #include <kernel/mutex.h>
void Kernel::Lock::lock() bool Kernel::Mutex::_lock()
{ {
/* check for the lock holder being the same cpu */ if (_current_cpu == Cpu::executing_id())
if (_current_cpu == Cpu::executing_id()) { return false;
/* at least print an error message */
Genode::raw("Cpu ", _current_cpu,
" error: re-entered lock. Kernel exception?!");
}
Cpu::wait_for_xchg(&_locked, LOCKED, UNLOCKED); Cpu::wait_for_xchg((volatile int*)&_locked, LOCKED, UNLOCKED);
_current_cpu = Cpu::executing_id(); _current_cpu = Cpu::executing_id();
return true;
} }
void Kernel::Lock::unlock() void Kernel::Mutex::_unlock()
{ {
_current_cpu = INVALID; _current_cpu = INVALID;