fix make for a21, PIDs are always ints, linter things

This commit is contained in:
Niklas Gollenstede
2026-01-05 10:41:27 +01:00
parent 7ae806fa01
commit 598f97cd78
16 changed files with 155 additions and 104 deletions

View File

@@ -1,6 +1,6 @@
FormatStyle: google FormatStyle: google
HeaderFilterRegex: '.*' HeaderFilterRegex: '.*'
WarningsAsErrors: 'readability*' #WarningsAsErrors: 'readability*'
Checks: > Checks: >
google-readability-casting, google-readability-casting,
google-explicit-constructor, google-explicit-constructor,
@@ -9,6 +9,7 @@ Checks: >
-readability-else-after-return, -readability-else-after-return,
-readability-function-cognitive-complexity -readability-function-cognitive-complexity
-readability-identifier-length, -readability-identifier-length,
-readability-implicit-bool-conversion,
-readability-magic-numbers, -readability-magic-numbers,
bugprone*, bugprone*,
-bugprone-easily-swappable-parameters, -bugprone-easily-swappable-parameters,
@@ -19,8 +20,11 @@ Checks: >
-cppcoreguidelines-avoid-do-while, -cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-non-private-member-variables-in-classes,
-cppcoreguidelines-owning-memory, -cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-*, -cppcoreguidelines-pro-*,
CheckOptions: CheckOptions:
readability-simplify-boolean-expr.IgnoreMacros: 'true' readability-simplify-boolean-expr.IgnoreMacros: 'true'
readability-identifier-length.IgnoreNames: 'g,me' readability-identifier-length.IgnoredVariableNames: '^(g|id|me)$'
readability-identifier-length.IgnoredParameterNames: '^(id|ms|p[1-5])$'
readability-identifier-length.IgnoredLoopCounterNames: '.*'

View File

@@ -10,13 +10,9 @@ constinit struct InterruptDescriptor idt[256] = {};
// Struct used for loading (the address of) the Interrupt Descriptor Table into // Struct used for loading (the address of) the Interrupt Descriptor Table into
// the IDT-Register // the IDT-Register
struct Register { struct Register {
uint16_t limit; // Address of the last valid byte (relative to base) uint16_t limit =
struct InterruptDescriptor* base; sizeof(idt) - 1; // Address of the last valid byte (relative to base)
explicit Register(uint8_t max = 255) { struct InterruptDescriptor* base = idt;
limit =
(max + static_cast<uint16_t>(1)) * sizeof(InterruptDescriptor) - 1;
base = idt;
}
} __attribute__((packed)); } __attribute__((packed));
static_assert(sizeof(InterruptDescriptor) == 16, static_assert(sizeof(InterruptDescriptor) == 16,
@@ -26,11 +22,11 @@ static_assert(alignof(decltype(idt)) % 8 == 0, "IDT must be 8 byte aligned!");
void load() { void load() {
// Create structure required for writing to idtr and load via lidt // Create structure required for writing to idtr and load via lidt
Register idtr(Core::Interrupt::VECTORS - 1); Register idtr;
asm volatile("lidt %0\n\t" ::"m"(idtr)); asm volatile("lidt %0\n\t" ::"m"(idtr));
} }
void set(Core::Interrupt::Vector vector, InterruptDescriptor descriptor) { void set(Core::Interrupt::Vector vector, InterruptDescriptor descriptor) {
idt[(uint8_t)vector] = descriptor; idt[static_cast<uint8_t>(vector)] = descriptor;
} }
} // namespace IDT } // namespace IDT

View File

@@ -1,7 +1,7 @@
#include "assert.h" #include "assert.h"
#include "../arch/core.h" #include "../arch/core.h"
#include "output.h" #include "./output.h"
[[noreturn]] void assertion_failed(const char* exp, const char* func, [[noreturn]] void assertion_failed(const char* exp, const char* func,
const char* file, int line) { const char* file, int line) {

View File

@@ -15,7 +15,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "types.h"
#ifndef STRINGIFY #ifndef STRINGIFY
/*! \def STRINGIFY(S) /*! \def STRINGIFY(S)

View File

@@ -25,18 +25,22 @@ class Queue {
/// Function pointer to the get_link function, called whenever the /// Function pointer to the get_link function, called whenever the
/// next pointer array is referenced /// next pointer array is referenced
const NextFunc get_link = default_get_link; const NextFunc get_link = default_get_link;
/// head points to the first element (the one returned on first dequeue). /// `head` points to the first element (the one returned on first dequeue).
/// Can be nullptr if the queue is empty. /// Can be `nullptr` if the queue is empty.
T* head = nullptr; T* head = nullptr;
/// tail points to the last element (the one last added). /// `tail` points to the last element (the one last added).
/// Is only valid if head != nullptr /// Is only valid if `head != nullptr`.
T* tail = nullptr; T* tail = nullptr;
// Prevent copies and assignments // Prevent copies and assignments
Queue(const Queue&) = delete; Queue(const Queue&) = delete;
Queue(Queue&&) = delete;
Queue& operator=(const Queue&) = delete; Queue& operator=(const Queue&) = delete;
Queue& operator=(Queue&&) = delete;
public: public:
~Queue() = default;
/*! \brief Minimal forward iterator /*! \brief Minimal forward iterator
* You can use this iterator to iterate the queue like a normal STL * You can use this iterator to iterate the queue like a normal STL
* container. It only supports forward iteration, since the queue is single * container. It only supports forward iteration, since the queue is single
@@ -44,11 +48,11 @@ class Queue {
*/ */
class Iterator { class Iterator {
private: private:
Queue<T>& queue; Queue<T>* queue;
T* current; T* current;
friend class Queue<T>; friend class Queue<T>;
Iterator(Queue<T>& queue, T* current) Iterator(Queue<T>& queue, T* current)
: queue(queue), current(current) {} : queue(&queue), current(current) {}
public: public:
Iterator operator+(unsigned num) { Iterator operator+(unsigned num) {
@@ -57,21 +61,21 @@ class Queue {
} }
T* temp = current; T* temp = current;
while (num--) { while (num--) {
temp = queue.next(*temp); temp = queue->next(*temp);
} }
return Iterator(queue, temp); return Iterator(*queue, temp);
} }
// pre increment // pre increment
Iterator& operator++() { Iterator& operator++() {
current = queue.next(*current); current = queue->next(*current);
return *this; return *this;
} }
// post increment // post increment
Iterator operator++(int) { Iterator operator++(int) {
auto temp = Iterator(queue, current); auto temp = Iterator(queue, current);
current = queue.next(*current); current = queue->next(*current);
return temp; return temp;
} }
@@ -84,8 +88,6 @@ class Queue {
bool operator!=(const Iterator& other) { return !(*this == other); } bool operator!=(const Iterator& other) { return !(*this == other); }
}; };
constexpr Queue(Queue&&) = default;
/*! \brief Constructor /*! \brief Constructor
* \param[in] get_link A function pointer to the get_link, i.e. a function * \param[in] get_link A function pointer to the get_link, i.e. a function
* which returns a pointer to the next-pointer of an * which returns a pointer to the next-pointer of an
@@ -97,11 +99,10 @@ class Queue {
"get_link function pointer must not be nullptr!"); "get_link function pointer must not be nullptr!");
} }
/*! \brief Enqueues the provided item at the end of the queue. If the /*! \brief Enqueues the provided item at the end of the queue.
*element is already contained in the queue, false will be returned * \param[in] item Element to be appended (enqueued).
* \param[in] item element to be appended (enqueued). * \return `false` if the element already was already in this (or a
* \return false if the element already was enqueued (and nothing was done) * different) queue (and nothing was done), `true` otherwise.
* or not (and it is now enqueued, then true)
*/ */
bool enqueue(T& item) { bool enqueue(T& item) {
T** nextptr = get_link(item); T** nextptr = get_link(item);
@@ -214,7 +215,7 @@ class Queue {
T* remove(T* that) { T* remove(T* that) {
if (!that) return nullptr; if (!that) return nullptr;
T* cur = head; T* cur = head;
T** next_link; T** next_link = nullptr;
if (head == that) { if (head == that) {
head = *get_link(*head); head = *get_link(*head);
@@ -258,14 +259,14 @@ class Queue {
* the pointer. * the pointer.
*/ */
template <class T> template <class T>
OutputStream& operator<<(OutputStream& os, Queue<T>& queue) { OutputStream& operator<<(OutputStream& out, Queue<T>& queue) {
os << "{"; out << "{";
for (typename Queue<T>::Iterator it = queue.begin(); it != queue.end(); for (typename Queue<T>::Iterator it = queue.begin(); it != queue.end();
++it) { ++it) {
os << *it; out << *it;
if (it + 1 != queue.end()) { if (it + 1 != queue.end()) {
os << ", "; out << ", ";
} }
} }
return os << "}"; return out << "}";
} }

View File

@@ -3,42 +3,13 @@
#include "../types.h" #include "../types.h"
struct Message { struct Message {
const size_t pid; ///< Sender Thread ID of message int sender; ///< Sender Thread ID of message
const uintptr_t sbuffer; ///< Send buffer uintptr_t sbuffer; ///< Send buffer
const size_t ssize; ///< Send buffer size size_t ssize; ///< Send buffer size
const uintptr_t rbuffer; ///< Receive buffer uintptr_t rbuffer; ///< Receive buffer
const size_t rsize; ///< Receive buffer size size_t rsize; ///< Receive buffer size
Message *queue_link = nullptr; ///< Next message in the message queue Message *queue_link = nullptr; ///< Next message in the message queue
/*! \brief Constructor
* \param pid Sender Thread ID of message
* \param sbuffer Send buffer
* \param ssize Send buffer size
* \param rbuffer Receive buffer
* \param rsize Receive buffer size
*/
explicit Message(int pid, uintptr_t sbuffer = 0, size_t ssize = 0,
uintptr_t rbuffer = 0, size_t rsize = 0)
: pid(pid),
sbuffer(sbuffer),
ssize(ssize),
rbuffer(rbuffer),
rsize(rsize) {}
/*! \brief Helper to retrieve (and remove) a message from the queue
* \param pid Thread id of message
* \param queue Queue with message
* \return Pointer to message or nullptr
*/
static Message *dequeueByPID(size_t pid, Queue<Message> &queue) {
for (Message *m : queue) {
if (m->pid == pid) {
return queue.remove(m);
}
}
return nullptr;
}
}; };

View File

@@ -24,15 +24,17 @@ class Thread;
class Semaphore { class Semaphore {
// Prevent copies and assignments // Prevent copies and assignments
Semaphore(const Semaphore&) = delete; Semaphore(const Semaphore&) = delete;
Semaphore(Semaphore&&) = delete;
Semaphore& operator=(const Semaphore&) = delete; Semaphore& operator=(const Semaphore&) = delete;
Semaphore& operator=(Semaphore&&) = delete;
unsigned counter; unsigned counter;
Queue<Thread> waiting; Queue<Thread> waiting;
public: public:
/*! \brief Constructor; initialized the counter with provided value `c` /*! \param init Initial counter value
* \param c Initial counter value
*/ */
explicit Semaphore(unsigned c = 0) : counter(c) {} explicit Semaphore(unsigned init = 0) : counter(init) {}
~Semaphore() = default;
/*! \brief Wait for access to the critical area. /*! \brief Wait for access to the critical area.
* *

View File

@@ -1,8 +1,6 @@
#include "syscall/skeleton.h" #include "syscall/skeleton.h"
#include "debug/kernelpanic.h"
#include "debug/output.h" #include "debug/output.h"
#include "device/textstream.h"
#include "interrupt/guard.h" #include "interrupt/guard.h"
#include "sync/semaphore.h" #include "sync/semaphore.h"
#include "thread/scheduler.h" #include "thread/scheduler.h"

View File

@@ -22,7 +22,7 @@ void sem_destroy(Vault &vault, size_t id);
void sem_signal(Vault &vault, size_t id); void sem_signal(Vault &vault, size_t id);
void sem_wait(Vault &vault, size_t id); void sem_wait(Vault &vault, size_t id);
void exit(Vault &vault); void exit(Vault &vault);
void kill(Vault &vault, size_t pid); void kill(Vault &vault, int pid);
} // namespace Skeleton } // namespace Skeleton
} // namespace Syscall } // namespace Syscall

View File

@@ -6,8 +6,7 @@
#include "../interrupt/guard.h" #include "../interrupt/guard.h"
#include "debug/output.h" #include "debug/output.h"
// counter for ID static int idCounter = 1; // counter for task IDs
static size_t idCounter = 1;
void Thread::kickoff(uintptr_t param1, uintptr_t param2, uintptr_t param3) { void Thread::kickoff(uintptr_t param1, uintptr_t param2, uintptr_t param3) {
Thread *thread = reinterpret_cast<Thread *>(param1); Thread *thread = reinterpret_cast<Thread *>(param1);

View File

@@ -28,14 +28,12 @@ class Thread {
/*! \brief pointer to the next element of the readylist /*! \brief pointer to the next element of the readylist
*/ */
Thread* queue_link; Thread* queue_link;
friend class Queue<Thread>; friend class Queue<Thread>;
friend class Semaphore; friend class Semaphore;
/*! \brief Memory reserved for this threads stack /*! \brief Memory reserved for this threads stack
*/ */
alignas(16) char reserved_stack_space[STACK_SIZE]; alignas(16) char reserved_stack_space[STACK_SIZE];
protected:
/*! \brief Context of the thread, used for saving and restoring the register /*! \brief Context of the thread, used for saving and restoring the register
* values when context switching. * values when context switching.
*/ */
@@ -56,17 +54,25 @@ class Thread {
* \param param1 Thread to be started * \param param1 Thread to be started
* \param param2 Second parameter (will be used later) * \param param2 Second parameter (will be used later)
* \param param3 Third parameter (will be used later) * \param param3 Third parameter (will be used later)
*
*/ */
static void kickoff(uintptr_t param1, uintptr_t param2, uintptr_t param3); static void kickoff(uintptr_t param1, uintptr_t param2, uintptr_t param3);
public: public:
/*! \brief Unique thread id */ /*! \brief Unique thread id */
const size_t id; const int id;
/*! \brief Marker for a dying thread /*! \brief Marker for a dying thread
*/ */
volatile bool kill_flag; volatile bool kill_flag;
// Naively moving or copying esp. the (user) stack of a thread would be a
// bad idea:
Thread(const Thread&) = delete;
Thread(Thread&&) = delete;
Thread& operator=(const Thread&) = delete;
Thread& operator=(Thread&&) = delete;
/*! \brief Constructor /*! \brief Constructor
* Initializes the context using \ref prepareContext with the thread's * Initializes the context using \ref prepareContext with the thread's
* stack space. * stack space.

View File

@@ -23,7 +23,7 @@ void Application::action() { // NOLINT
// Make sure that we can use kout exclusively due to the hardware cursor // Make sure that we can use kout exclusively due to the hardware cursor
// otherwise we'd get a word jumble // otherwise we'd get a word jumble
koutsem.p(Guard::enter().vault()); koutsem.p(Guard::enter().vault());
kout.setPos(0U, id); kout.setPos(0U, static_cast<unsigned>(id));
kout << i; kout << i;
kout.flush(); kout.flush();
koutsem.v(Guard::enter().vault()); koutsem.v(Guard::enter().vault());

74
libsys/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

View File

@@ -19,14 +19,16 @@ $(APPS): $(BUILDDIR)/init.o
# recipe for compiling imgbuilder # recipe for compiling imgbuilder
$(IMGBUILDER): imgbuilder.cc $(MAKEFILE_LIST) $(IMGBUILDER): imgbuilder.cc $(MAKEFILE_LIST)
@echo "CC $@" @echo "CXX $@"
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi @mkdir -p $(@D)
$(VERBOSE) $(CXX) -std=c++23 -o $@ $< $(VERBOSE) $(CXX) -std=c++23 -o $@ $<
# recipe for building the final oostubs image .ONESHELL:
# recipe for building the initrd image
$(INITRD): $(APPS) $(IMGBUILDER) $(INITRD): $(APPS) $(IMGBUILDER)
@echo "IMGBUILD $@" @echo "IMGBUILD $@"
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi @mkdir -p $(@D)
if [ -z "$(APPS)" ] ; then touch $@ ; exit 0 ; fi
$(VERBOSE) $(IMGBUILDER) $(addsuffix $(BUILDDIR)/app.img, $(APPS)) > $@ $(VERBOSE) $(IMGBUILDER) $(addsuffix $(BUILDDIR)/app.img, $(APPS)) > $@
lint:: lint::

View File

@@ -41,7 +41,7 @@ $(BUILDDIR)/app: $(INITOBJ) $(ASM_OBJECTS) $(CC_OBJECTS) $(LINKER_SCRIPT) $(MAK
$(BUILDDIR)/app.img: $(BUILDDIR)/app $(BUILDDIR)/app.img: $(BUILDDIR)/app
@echo "OBJCOPY $@" @echo "OBJCOPY $@"
@if ! nm $< | grep "4000000 T start" >/dev/null 2>&1 ; then echo "Symbol 'start' is not first address" ; exit 1 ; fi @if ! nm $< | grep "4000000 T start" >/dev/null 2>&1 ; then echo "Symbol 'start' is not first address" ; exit 1 ; fi
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi @mkdir -p $(@D)
$(VERBOSE) objcopy -O binary --set-section-flags .bss=alloc,load,contents $< $@ $(VERBOSE) objcopy -O binary --set-section-flags .bss=alloc,load,contents $< $@
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------

View File

@@ -10,7 +10,7 @@
#include <print> #include <print>
#include <vector> #include <vector>
constexpr size_t block_size = 4096; constexpr std::streamsize block_size = 4096;
const uint8_t zeros[block_size] = {}; const uint8_t zeros[block_size] = {};
template <class... Args> template <class... Args>
@@ -20,7 +20,7 @@ static void die(std::format_string<Args...> fmt, Args &&...args) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static void writeBuffer(const void *data, size_t size) { static void writeBuffer(const void *data, std::streamsize size) {
std::cout.write(reinterpret_cast<const char *>(data), size); std::cout.write(reinterpret_cast<const char *>(data), size);
} }
@@ -33,35 +33,33 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// HEADER: Number of apps + size of each app // HEADER: Number of apps + size of each app in bytes
std::array<uint32_t, block_size / sizeof(uint32_t)> size{0}; std::array<uint32_t, block_size / sizeof(uint32_t)> sizes{0};
size[0] = static_cast<uint32_t>(argc - 1); sizes[0] = static_cast<uint32_t>(argc - 1);
for (size_t i = 1; i < argc; ++i) { for (size_t i = 1; i < argc; ++i) {
struct stat sb; struct stat file;
if (stat(argv[i], &sb) != 0) die("stat"); if (stat(argv[i], &file) != 0) die("stat");
// 4 GB Limit if (file.st_size >= UINT32_MAX) { // 4 GB Limit
if (sb.st_size >= UINT32_MAX) {
errno = EFBIG; errno = EFBIG;
die("stat"); die("stat");
} }
size[i] = sb.st_size; sizes[i] = file.st_size;
} }
writeBuffer(size.data(), block_size); writeBuffer(sizes.data(), block_size);
// DATA: Each App // DATA: Each App
for (size_t i = 1; i < argc; ++i) { for (size_t i = 1; i < argc; ++i) {
std::vector<char> buf(size[i]); std::vector<char> buf(sizes[i]);
std::ifstream input(argv[i], std::ios::binary); std::ifstream input(argv[i], std::ios::binary);
if (!input) die("fopen"); if (!input) die("fopen");
input.read(buf.data(), size[i]); input.read(buf.data(), sizes[i]);
writeBuffer(buf.data(), size[i]); writeBuffer(buf.data(), sizes[i]);
// Fill to block size, if required // Fill to block size, if required
if (size[i] % block_size != 0) if (sizes[i] % block_size != 0)
writeBuffer(zeros, block_size - (size[i] % block_size)); writeBuffer(zeros, block_size - (sizes[i] % block_size));
} }
std::cout.flush(); std::cout.flush();