Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1437bcb
fix(vsprintf): handle NULL string pointers gracefully
Galfurian Feb 4, 2026
53e2823
fix(elf): disable COW for initial PT_LOAD segments
Galfurian Feb 4, 2026
2a15d4a
fix(mm): disable COW for initial user stack
Galfurian Feb 4, 2026
a471862
fix(timer): only schedule on user-mode interrupts
Galfurian Feb 4, 2026
7ff97af
refactor(ps2): improve code organization with section headers and fix…
Galfurian Feb 6, 2026
13522fa
refactor(ps2): extract helper functions for common patterns
Galfurian Feb 6, 2026
3c9e73f
fix(rtc): use inline assembly to prevent Release-mode optimization
Galfurian Feb 6, 2026
065fec2
refactor(rtc): consolidate CMOS reads into single helper function
Galfurian Feb 6, 2026
d8c96eb
Set notice as debug level in RTC.
Galfurian Feb 6, 2026
483d79a
fix(test_paging): resolve Release-mode failures in paging unit tests
Galfurian Feb 6, 2026
3bd552c
refactor(exception): simplify ISR macros and normalize pt_regs stack …
Galfurian Feb 6, 2026
4bbcda8
fix(exception): simplify ISR handling and make PRINT_REGS safe for ke…
Galfurian Feb 6, 2026
4b1f0dd
fix(Release): volatile reads in spinlocks, mutexes, and scheduler con…
Galfurian Feb 6, 2026
c3fce4e
fix(timer): volatile reads on timer_ticks in event loop
Galfurian Feb 6, 2026
dee1db5
fix(timer): correct volatile cast type from uint32_t to unsigned long
Galfurian Feb 6, 2026
52d8b54
Merge branch 'develop' into feature/debug-double-fault
Galfurian Feb 9, 2026
15eeb3a
fix(io): correct I/O port inline assembly constraints
Galfurian Feb 9, 2026
2d3cc85
chore: revert temporary debug changes
Galfurian Feb 9, 2026
2222860
chore(kernel): tidy logging in ps2 and allocators
Galfurian Feb 9, 2026
8c23381
build(cmake): adjust qemu and optimization flags
Galfurian Feb 9, 2026
6ffe51c
refactor(stack): replace stack macros with helpers
Galfurian Feb 9, 2026
48d4665
fix(module): treat missing modules as success
Galfurian Feb 9, 2026
a6bb45d
fix(fpu): handle default SIGILL
Galfurian Feb 9, 2026
ab1723b
style(signal): align signal enum
Galfurian Feb 9, 2026
f7b9644
fix(tests): Fix some of the tests.
Galfurian Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 29 additions & 24 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ cmake_minimum_required(VERSION 3.1...3.22)
# Initialize the project.
project(mentos C ASM)

# Set the default build type to Debug.
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to 'Debug' as none was specified.")
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE)
endif()
# Add the CMAKE_BUILD_TYPE option with the full list of possible values.
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build: Debug, Release, RelWithDebInfo, MinSizeRel")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo" "MinSizeRel")

# -----------------------------------------------------------------------------
# ENABLE FETCH CONTENT
Expand Down Expand Up @@ -48,21 +46,21 @@ if((${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin") OR APPLE)
# Specify the linker flags.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostdlib")
elseif((${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") OR WIN32)
# Windows set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -sdl)
# Windows set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -sdl)
else()
# Generic Unix System.
# Find the `lsb_release` program.
find_program(LSB_RELEASE_EXEC lsb_release HINTS /usr/bin/ /usr/local/bin/)
mark_as_advanced(LSB_RELEASE_EXEC)

if(LSB_RELEASE_EXEC)
execute_process(
COMMAND "${LSB_RELEASE_EXEC}" --short --release
OUTPUT_VARIABLE LSB_RELEASE_VERSION_SHORT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "LSB version : ${LSB_RELEASE_VERSION_SHORT}")

# Use GTK display for Ubuntu 19+
if(LSB_RELEASE_VERSION_SHORT MATCHES "^(19|2[0-9])")
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -display gtk)
Expand Down Expand Up @@ -105,7 +103,7 @@ set(CMAKE_ASM_COMPILER ${ASM_COMPILER})
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -f elf -g -O0 -F dwarf -o <OBJECT> <SOURCE>")
else()
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -f elf -g -O3 -o <OBJECT> <SOURCE>")
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -f elf -g -O2 -o <OBJECT> <SOURCE>")
endif()

# =============================================================================
Expand Down Expand Up @@ -153,7 +151,7 @@ endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3 -ggdb -O0")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
endif()

# Set the assembly compiler flags.
Expand Down Expand Up @@ -198,9 +196,13 @@ set(EMULATOR qemu-system-i386)
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -vga std)
# Set the amount of memory.
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -m 1096M)
# Set the RTC to use local time.
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -rtc base=localtime)
# Disables all default devices (e.g., serial ports, network cards, VGA
# adapters). Only devices we explicitly specify will be added.
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -nodefaults)
# Disable reboot and shutdown.
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -no-reboot)
# Set the debug type.
if(${EMULATOR_OUTPUT_TYPE} STREQUAL OUTPUT_LOG)
set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -serial file:${CMAKE_BINARY_DIR}/serial.log)
Expand Down Expand Up @@ -271,11 +273,13 @@ add_custom_target(

# First, we need to build the ISO for the cdrom.
add_custom_target(
cdrom.iso
COMMAND cp -rf ${CMAKE_SOURCE_DIR}/iso .
COMMAND cp ${CMAKE_BINARY_DIR}/mentos/bootloader.bin ${CMAKE_BINARY_DIR}/iso/boot
COMMAND grub-mkrescue -o ${CMAKE_BINARY_DIR}/cdrom.iso ${CMAKE_BINARY_DIR}/iso
DEPENDS bootloader.bin
cdrom.iso
COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_BINARY_DIR}/iso
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/iso ${CMAKE_BINARY_DIR}/iso
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/mentos/bootloader.bin ${CMAKE_BINARY_DIR}/iso/boot/bootloader.bin
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/iso/boot/grub/grub.cfg ${CMAKE_BINARY_DIR}/iso/boot/grub/grub.cfg
COMMAND grub-mkrescue -o ${CMAKE_BINARY_DIR}/cdrom.iso ${CMAKE_BINARY_DIR}/iso
DEPENDS bootloader.bin
)

# This third target runs the emualtor, but this time, the kernel binary file is
Expand All @@ -295,11 +299,12 @@ add_custom_target(
# First, we need to build the ISO for the cdrom. It has a slightly different
# kernel command line including 'test'.
add_custom_target(
cdrom_test.iso
COMMAND cp -rf ${CMAKE_SOURCE_DIR}/iso .
COMMAND mv ${CMAKE_BINARY_DIR}/iso/boot/grub/grub.cfg.runtests ${CMAKE_BINARY_DIR}/iso/boot/grub/grub.cfg
COMMAND cp ${CMAKE_BINARY_DIR}/mentos/bootloader.bin ${CMAKE_BINARY_DIR}/iso/boot
COMMAND grub-mkrescue -o ${CMAKE_BINARY_DIR}/cdrom_test.iso ${CMAKE_BINARY_DIR}/iso
cdrom_test.iso
COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_BINARY_DIR}/iso_test
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/iso ${CMAKE_BINARY_DIR}/iso_test
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/iso/boot/grub/grub.cfg.runtests ${CMAKE_BINARY_DIR}/iso_test/boot/grub/grub.cfg
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/mentos/bootloader.bin ${CMAKE_BINARY_DIR}/iso_test/boot/bootloader.bin
COMMAND grub-mkrescue -o ${CMAKE_BINARY_DIR}/cdrom_test.iso ${CMAKE_BINARY_DIR}/iso_test
DEPENDS bootloader.bin filesystem
)

Expand All @@ -308,7 +313,7 @@ add_custom_target(
# after the tests are done.
add_custom_target(
qemu-test
COMMAND ${EMULATOR} ${EMULATOR_FLAGS} -serial file:${CMAKE_BINARY_DIR}/test.log -nographic -device isa-debug-exit -boot d -cdrom ${CMAKE_BINARY_DIR}/cdrom_test.iso
COMMAND ${EMULATOR} ${EMULATOR_FLAGS} -nographic -device isa-debug-exit -boot d -cdrom ${CMAKE_BINARY_DIR}/cdrom_test.iso
DEPENDS cdrom_test.iso
)

Expand Down Expand Up @@ -356,8 +361,8 @@ endif()
# DOCUMENTATION
# -----------------------------------------------------------------------------

if (DOXYGEN_FOUND)
if(DOXYGEN_FOUND)

# FetchContent: Doxygen Awesome CSS
FetchContent_Declare(doxygenawesome
GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css
Expand Down Expand Up @@ -431,4 +436,4 @@ if (DOXYGEN_FOUND)
${ALL_PROJECT_FILES}
COMMENT "Generating Doxygen documentation"
)
endif (DOXYGEN_FOUND)
endif(DOXYGEN_FOUND)
7 changes: 5 additions & 2 deletions kernel/inc/io/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ struct pt_regs;
dbg_fn(" EIP = 0x%-09x\n", (frame)->eip); \
dbg_fn(" CS = 0x%-04x\n", (frame)->cs); \
dbg_fn(" EFLAGS = 0x%-09x\n", (frame)->eflags); \
dbg_fn(" UESP = 0x%-09x\n", (frame)->useresp); \
dbg_fn(" SS = 0x%-04x\n", (frame)->ss); \
/* Only print user mode stack info if exception came from user mode (CS privilege bits = 3) */ \
if (((frame)->cs & 0x3) == 3) { \
dbg_fn(" UESP = 0x%-09x\n", (frame)->useresp); \
dbg_fn(" SS = 0x%-04x\n", (frame)->ss); \
} \
} while (0)
120 changes: 104 additions & 16 deletions kernel/inc/klib/stack_helper.h
Original file line number Diff line number Diff line change
@@ -1,22 +1,110 @@
/// @file stack_helper.h
/// @brief Couple of macros that help accessing the stack.
/// @brief Inline functions for safe stack manipulation with proper sequencing.
/// @copyright (c) 2014-2024 This file is distributed under the MIT License.
/// See LICENSE.md for details.

#pragma once

/// @brief Access the value of the pointer.
#define __ACCESS_PTR(type, ptr) (*(type *)(ptr))
/// @brief Moves the pointer down.
#define __MOVE_PTR_DOWN(type, ptr) ((ptr) -= sizeof(type))
/// @brief Moves the pointer up.
#define __MOVE_PTR_UP(type, ptr) ((ptr) += sizeof(type))
/// @brief First, it moves the pointer down, and then it pushes the value at that memory location.
#define PUSH_VALUE_ON_STACK(ptr, value) \
(__ACCESS_PTR(__typeof__(value), __MOVE_PTR_DOWN(__typeof__(value), ptr)) = (value))
/// @brief First, it access the value at the given memory location, and then it moves the pointer up.
#define POP_VALUE_FROM_STACK(value, ptr) \
({ \
(value) = __ACCESS_PTR(__typeof__(value), ptr); \
__MOVE_PTR_UP(__typeof__(value), ptr); \
})
#include <stddef.h>
#include <stdint.h>
#include <string.h>

/// @brief Push a 32-bit value onto the stack, decrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be decremented).
/// @param value The 32-bit value to push.
static inline void stack_push_u32(uint32_t *sp, uint32_t value)
{
*sp -= sizeof(uint32_t);
__asm__ __volatile__("" ::: "memory");
*(volatile uint32_t *)(*sp) = value;
__asm__ __volatile__("" ::: "memory");
}

/// @brief Push a signed 32-bit value onto the stack, decrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be decremented).
/// @param value The signed 32-bit value to push.
static inline void stack_push_s32(uint32_t *sp, int32_t value)
{
*sp -= sizeof(int32_t);
__asm__ __volatile__("" ::: "memory");
*(volatile int32_t *)(*sp) = value;
__asm__ __volatile__("" ::: "memory");
}

/// @brief Push a pointer value onto the stack, decrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be decremented).
/// @param ptr The pointer value to push.
static inline void stack_push_ptr(uint32_t *sp, const void *ptr)
{
*sp -= sizeof(uint32_t);
__asm__ __volatile__("" ::: "memory");
*(volatile uint32_t *)(*sp) = (uint32_t)ptr;
__asm__ __volatile__("" ::: "memory");
}

/// @brief Push a single byte onto the stack, decrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be decremented).
/// @param byte The byte value to push.
static inline void stack_push_u8(uint32_t *sp, uint8_t byte)
{
*sp -= sizeof(uint8_t);
__asm__ __volatile__("" ::: "memory");
*(volatile uint8_t *)(*sp) = byte;
__asm__ __volatile__("" ::: "memory");
}

/// @brief Pop a 32-bit value from the stack, incrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be incremented).
/// @return The 32-bit value popped from the stack.
static inline uint32_t stack_pop_u32(uint32_t *sp)
{
uint32_t value = *(volatile uint32_t *)(*sp);
__asm__ __volatile__("" ::: "memory");
*sp += sizeof(uint32_t);
return value;
}

/// @brief Pop a signed 32-bit value from the stack, incrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be incremented).
/// @return The signed 32-bit value popped from the stack.
static inline int32_t stack_pop_s32(uint32_t *sp)
{
int32_t value = *(volatile int32_t *)(*sp);
__asm__ __volatile__("" ::: "memory");
*sp += sizeof(int32_t);
return value;
}

/// @brief Pop a pointer value from the stack, incrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be incremented).
/// @return The pointer value popped from the stack.
static inline void *stack_pop_ptr(uint32_t *sp)
{
void *value = (void *)*(volatile uint32_t *)(*sp);
__asm__ __volatile__("" ::: "memory");
*sp += sizeof(uint32_t);
return value;
}

/// @brief Push arbitrary data onto the stack, decrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be decremented by size).
/// @param data Pointer to data to push.
/// @param size Number of bytes to push.
static inline void stack_push_data(uint32_t *sp, const void *data, size_t size)
{
*sp -= size;
__asm__ __volatile__("" ::: "memory");
memcpy((void *)*sp, data, size);
__asm__ __volatile__("" ::: "memory");
}

/// @brief Pop arbitrary data from the stack, incrementing the stack pointer.
/// @param sp Pointer to 32-bit stack pointer (will be incremented by size).
/// @param data Pointer to buffer where popped data will be stored.
/// @param size Number of bytes to pop.
static inline void stack_pop_data(uint32_t *sp, void *data, size_t size)
{
memcpy(data, (void *)*sp, size);
__asm__ __volatile__("" ::: "memory");
*sp += size;
}
19 changes: 9 additions & 10 deletions kernel/inc/system/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@

/// @brief Signal codes.
typedef enum {
SIGHUP = 1, ///< Hang up detected on controlling terminal or death of controlling process.
SIGINT = 2, ///< Issued if the user sends an interrupt signal (Ctrl + C).
SIGQUIT = 3, ///< Issued if the user sends a quit signal (Ctrl + D).
SIGILL = 4, ///< Illegal Instruction.
SIGTRAP = 5, ///< Trace/breakpoint trap.
SIGABRT = 6, ///< Abort signal from abort().
SIGEMT = 7, ///< Emulator trap.
SIGFPE = 8, ///< Floating-point arithmetic exception.
SIGKILL =
9, ///< If a process gets this signal it must quit immediately and will not perform any clean-up operations.
SIGHUP = 1, ///< Hang up detected on controlling terminal or death of controlling process.
SIGINT = 2, ///< Issued if the user sends an interrupt signal (Ctrl + C).
SIGQUIT = 3, ///< Issued if the user sends a quit signal (Ctrl + D).
SIGILL = 4, ///< Illegal Instruction.
SIGTRAP = 5, ///< Trace/breakpoint trap.
SIGABRT = 6, ///< Abort signal from abort().
SIGEMT = 7, ///< Emulator trap.
SIGFPE = 8, ///< Floating-point arithmetic exception.
SIGKILL = 9, ///< If a process gets this signal it must quit immediately and will not perform any clean-up operations.
SIGBUS = 10, ///< Bus error (bad memory access).
SIGSEGV = 11, ///< Invalid memory reference.
SIGSYS = 12, ///< Bad system call (SVr4).
Expand Down
Loading