This commit is contained in:
Niklas Gollenstede
2025-10-31 22:37:36 +01:00
commit 174fe17e89
197 changed files with 79558 additions and 0 deletions

11
kernel/debug/assert.cc Normal file
View File

@@ -0,0 +1,11 @@
#include "assert.h"
#include "../arch/core.h"
#include "output.h"
[[noreturn]] void assertion_failed(const char* exp, const char* func,
const char* file, int line) {
DBG << "Assertion '" << exp << "' failed (" << func << " @ " << file << ":"
<< dec << line << ") - CPU stopped." << endl;
Core::die();
}

74
kernel/debug/assert.h Normal file
View File

@@ -0,0 +1,74 @@
// vim: set noet ts=4 sw=4:
/*! \file
* \brief Contains several macros usable for making assertions
*
* Depending on the type of assertion (either static or at runtime), a failing
* assertion will trigger an error. For static assertion, this error will be
* shown at compile time and abort compilation. Runtime assertions will trigger
* a message containing details about the error occurred and will make the CPU
* die.
*/
/*!
* \defgroup debug Debugging functions
*/
#pragma once
#include "../types.h"
#ifndef STRINGIFY
/*! \def STRINGIFY(S)
* \brief Converts a macro parameter into a string
* \ingroup debug
* \param S Expression to be converted
* \return stringified version of S
*/
#define STRINGIFY(S) #S
#endif
/*! \def assert_size(TYPE, SIZE)
* \brief Statically ensure (at compile time) that a data type (or variable)
* has the expected size.
*
* \ingroup debug
* \param TYPE The type to be checked
* \param SIZE Expected size in bytes
*/
#define assert_size(TYPE, SIZE) \
static_assert(sizeof(TYPE) == (SIZE), "Wrong size for " STRINGIFY(TYPE))
/*! \def assert(EXP)
* \brief Ensure (at execution time) an expression evaluates to `true`, print
* an error message and stop the CPU otherwise.
*
* \ingroup debug
* \param EXP The expression to be checked
*/
#ifdef NDEBUG
#define assert(EXP) ((void)0)
#else
#define assert(EXP) \
do { \
if (__builtin_expect(!(EXP), 0)) { \
assertion_failed(STRINGIFY(EXP), __func__, __FILE__, __LINE__); \
} \
} while (false)
/*! \brief Handles a failed assertion
*
* This function will print a message containing further information about the
* failed assertion and stops the current CPU permanently.
*
* \note This function should never be called directly, but only via the macro
* `assert`.
*
*
* \param exp Expression that did not hold
* \param func Name of the function in which the assertion failed
* \param file Name of the file in which the assertion failed
* \param line Line in which the assertion failed
*/
[[noreturn]] void assertion_failed(const char* exp, const char* func,
const char* file, int line);
#endif

44
kernel/debug/copystream.h Normal file
View File

@@ -0,0 +1,44 @@
/*! \file
* \brief \ref CopyStream duplicates \ref OutputStream "output streams"
*/
#pragma once
#include "../object/outputstream.h"
#include "../types.h"
/*! \brief Duplicate all data passed by the stream operator to two \ref
* OutputStream "output streams"
* \ingroup io
*
* Can be used as replacement for any \ref OutputStream -- for example,
* forwarding the \ref DBG output simultaneously to screen (\ref TextStream) and
* serial console (\ref SerialStream).
*
*/
class CopyStream : public OutputStream {
/*! \brief First recipient
*/
OutputStream* first;
/*! \brief Second recipient
*/
OutputStream* second;
public:
/*! \brief Constructor
*
* \param first First recipient for output passed to this object
* \param second Second recipient for output passed to this object
*/
CopyStream(OutputStream* first, OutputStream* second)
: first(first), second(second) {}
/*! \brief Redirect the buffer to both streams and flush them, too.
*/
void flush() override {
buffer[pos] = '\0'; // make sure buffer will only be printed until pos.
*first << buffer << ::flush;
*second << buffer << ::flush;
pos = 0;
}
};

View File

@@ -0,0 +1,27 @@
// vim: set noet ts=4 sw=4:
/*! \file
* \brief Macro to print an error message and stop the current core.
*/
#pragma once
#include "../types.h"
/*! \def kernelpanic
* \brief Print an error message in the debug window and \ref Core::die "stop
* the current core"
*
* \param MSG error message
* \ingroup debug
*/
#define kernelpanic(MSG) \
do { \
DBG << "PANIC: '" << (MSG) << "' in " << __func__ << " @ " << __FILE__ \
<< ":" << __LINE__ << ") - CPU stopped." << endl; \
Core::die(); \
} while (0)
// The includes are intentionally placed at the end, so the macro can be used
// inside those included files as well.
#include "../arch/core.h"
#include "./output.h"

View File

@@ -0,0 +1,4 @@
#include "nullstream.h"
// Instance
NullStream nullstream;

45
kernel/debug/nullstream.h Normal file
View File

@@ -0,0 +1,45 @@
/*! \file
* \brief \ref NullStream is a stream discarding everything
*/
#pragma once
#include "../object/outputstream.h"
#include "../types.h"
/*! \brief Ignore all data passed by the stream operator
* \ingroup io
*
* Can be used instead of the \ref OutputStream if (for debugging reasons) all
* output should be ignored, e.g. for \ref DBG_VERBOSE
*
* By using template programming, a single generic methods is sufficient
* (which simply discard everything).
*/
class NullStream {
/*! \brief Check if type is supported by output stream
*/
template <typename T>
auto check(T v, OutputStream* p = nullptr) -> decltype(*p << v, void()) {}
public:
/*! \brief Empty default constructor
*/
NullStream() {}
/*! \brief Generic stream operator for any data type
*
* Uses template meta programming for a generic & short solution
*
* \tparam T Type of data to ignore
* \param value data to be ignore
* \return Reference to the \ref NullStream object allowing concatenation of
* operators
*/
template <typename T>
NullStream& operator<<(T value) {
check(value);
return *this;
}
};
extern NullStream nullstream;

69
kernel/debug/output.h Normal file
View File

@@ -0,0 +1,69 @@
// vim: set noet ts=4 sw=4:
/*! \file
* \brief Debug macros enabling debug output on a separate window for each
* core.
*/
#pragma once
#include "../object/outputstream.h"
#include "../types.h"
#include "nullstream.h"
/*! \def DBG_VERBOSE
* \brief An output stream, which is only displayed in the debug window in
* verbose mode
*
* \note If a serial console has been implemented, the output can be redirected
* to the serial stream instead (by changing the macro) -- this makes the
* (usually) very large output more readable (since it allows scrolling
* back)
*/
#ifdef VERBOSE
// If VERBOSE is defined, forward everything to \ref DBG
#define DBG_VERBOSE (DBG << __FILE__ << ":" << __LINE__ << " ")
#else
// Otherwise sent everything to the NullStream (which will simply discard
// everything)
#define DBG_VERBOSE nullstream
#endif
/*! \def DBG
* \brief An output stream, which is displayed in the debug window
*
* This is also used by the \ref assert macro and its underlying \ref
* assertion_failed method.
*
* In single core (\OOStuBS) this is just an alias to the debug window object
* `dout`.
*/
#define DBG *copyout
#include "../device/textstream.h"
/*! \brief Debug window
*
* Debug output using \ref DBG like
* `DBG << "var = " << var << endl`
* should be displayed in separate window.
*
* Ideally, this window should be placed below the normal output window
* without any overlap and be able to display 4 lines.
*
*/
extern TextStream dout;
/*! \brief Debug window with copy function to serial
*
* Provide an additional layer to also ouput debug prints to serial.
* While this is a simple CopyStream pointer in the single core case, it is
* an array in the multi core case, which consists of three TextStreams and
* one CopyStream.
* For that, construction is done like:
*
* \code{.cpp}
* OutputStream* copyout[Core::MAX]{&dout[0], &dout[1], ...}
* \endcode
*
*/
extern OutputStream* copyout;