hw: don't take the log backend's mutex in kernel

To prevent the kernel to deadlock, or call itself with a syscall when
using a lock potentially hold by a core thread, the log console's
backend for core (hw) gets replaced by a specific variant that checks
whether it runs in the kernel context before using the mutex.

Fix genodelabs/genode#3280
This commit is contained in:
Stefan Kalkowski 2022-12-16 14:33:06 +01:00 committed by Christian Helmuth
parent b59ec55d50
commit 8fe7fa5532
3 changed files with 86 additions and 1 deletions

View File

@ -10,3 +10,8 @@ include $(BASE_DIR)/lib/mk/base-common.inc
SRC_CC += rpc_dispatch_loop.cc SRC_CC += rpc_dispatch_loop.cc
SRC_CC += thread.cc thread_myself.cc thread_bootstrap.cc SRC_CC += thread.cc thread_myself.cc thread_bootstrap.cc
SRC_CC += signal_transmitter.cc SRC_CC += signal_transmitter.cc
# filter out log.cc from the generic base library
# in core and hw kernel we have to implement it differently
SRC_CC_WITH_LOG_CC := $(SRC_CC)
SRC_CC = $(filter-out log.cc,$(SRC_CC_WITH_LOG_CC))

View File

@ -1,5 +1,6 @@
include $(BASE_DIR)/lib/mk/base.inc include $(BASE_DIR)/lib/mk/base.inc
SRC_CC += log.cc
SRC_CC += thread_start.cc SRC_CC += thread_start.cc
SRC_CC += capability.cc SRC_CC += capability.cc
SRC_CC += cache.cc SRC_CC += cache.cc

View File

@ -12,15 +12,22 @@
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
*/ */
/* Genode includes */
#include <base/log.h>
#include <base/thread.h>
/* base-internal includes */ /* base-internal includes */
#include <base/internal/output.h> #include <base/internal/output.h>
#include <base/internal/raw_write_string.h> #include <base/internal/raw_write_string.h>
#include <core_log.h> #include <core_log.h>
#include <kernel/cpu.h>
#include <kernel/log.h> #include <kernel/log.h>
using namespace Genode;
void Genode::Core_log::out(char const c) { Kernel::log(c); }
void Core_log::out(char const c) { Kernel::log(c); }
void Genode::raw_write_string(char const *str) void Genode::raw_write_string(char const *str)
@ -28,3 +35,75 @@ void Genode::raw_write_string(char const *str)
while (char c = *str++) while (char c = *str++)
Kernel::log(c); Kernel::log(c);
} }
/************************************************************
** Utility to check whether kernel or core code is active **
************************************************************/
extern void const * const kernel_stack;
static inline bool running_in_kernel()
{
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
static constexpr size_t stack_size =
NR_OF_CPUS * Kernel::Cpu::KERNEL_STACK_SIZE;
/* check stack variable against kernel stack area */
return ((addr_t)&stack_base) >= stack_base &&
((addr_t)&stack_base) < (stack_base + stack_size);
}
/*******************************************
** Implementation of src/lib/base/log.cc **
*******************************************/
void Log::_acquire(Type type)
{
if (!running_in_kernel()) _mutex.acquire();
/*
* Mark warnings and errors via distinct colors.
*/
switch (type) {
case LOG: break;
case WARNING: _output.out_string("\033[34mWarning: "); break;
case ERROR: _output.out_string("\033[31mError: "); break;
};
}
void Log::_release()
{
/*
* Reset color and add newline
*/
_output.out_string("\033[0m\n");
if (!running_in_kernel()) _mutex.release();
}
void Raw::_acquire()
{
/*
* Mark raw output with distinct color
*/
_output().out_string("\033[32mKernel: ");
}
void Raw::_release()
{
/*
* Reset color and add newline
*/
_output().out_string("\033[0m\n");
}
void Trace_output::Write_trace_fn::operator () (char const *s)
{
Thread::trace(s);
}