mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-11 04:53:04 +00:00
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:
parent
c2cee1a885
commit
98032a2605
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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_ */
|
|
@ -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,35 +101,34 @@ 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) {
|
||||||
|
nr_of_initialized_cpus = 0;
|
||||||
|
|
||||||
if (nr_of_initialized_cpus == nr_of_cpus) {
|
Main::_instance->_serial.init();
|
||||||
nr_of_initialized_cpus = 0;
|
Main::_instance->_global_irq_ctrl.init();
|
||||||
|
}
|
||||||
|
|
||||||
Main::_instance->_serial.init();
|
nr_of_initialized_cpus = nr_of_initialized_cpus + 1;
|
||||||
Main::_instance->_global_irq_ctrl.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
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) { }
|
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
|
/**
|
||||||
* CPU pool.
|
* 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->_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,29 +163,30 @@ 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()) {
|
||||||
|
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->_core_main_thread.construct(
|
||||||
Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) {
|
Main::_instance->_addr_space_id_alloc,
|
||||||
boot_info.kernel_irqs.add(cpu.timer().interrupt_id());
|
Main::_instance->_user_irq_pool,
|
||||||
});
|
Main::_instance->_cpu_pool,
|
||||||
boot_info.kernel_irqs.add((unsigned)Board::Pic::IPI);
|
Main::_instance->_core_platform_pd.kernel_pd());
|
||||||
|
|
||||||
Main::_instance->_core_main_thread.construct(
|
boot_info.core_main_thread_utcb =
|
||||||
Main::_instance->_addr_space_id_alloc,
|
(addr_t)Main::_instance->_core_main_thread->utcb();
|
||||||
Main::_instance->_user_irq_pool,
|
|
||||||
Main::_instance->_cpu_pool,
|
|
||||||
Main::_instance->_core_platform_pd.kernel_pd());
|
|
||||||
|
|
||||||
boot_info.core_main_thread_utcb =
|
Genode::log("");
|
||||||
(addr_t)Main::_instance->_core_main_thread->utcb();
|
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
|
* Let secondary CPUs block until the primary CPU has initialized the
|
||||||
|
@ -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;
|
||||||
|
|
62
repos/base-hw/src/core/kernel/mutex.h
Normal file
62
repos/base-hw/src/core/kernel/mutex.h
Normal 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_ */
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user