From 9ff6bf983a40ae30472962343036a5b6d9d00e25 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 3 Sep 2026 21:02:08 +0200 Subject: x86_64/cpu: fix GDT size calculation The GDT pointer already receives the size in bytes when the GDT constructs it to activate the new GDT. Previously, the size in bytes got multiplied by the size of a single segment_descriptor before performing the mandatory subtraction of one. This means that the CPU lived in the believe that the GDT had a size of 448 bytes, instead of the true 56. Additionally, the calculation was flawed in another way, revealing the reason for why the size in bytes was passed to global_descriptor_table_pointer in the first place: it assumes that all entries in the GDT are of the same size. However, system descriptors are larger than basic segment descriptors. --- arch/x86_64/arch/cpu/global_descriptor_table.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/arch/cpu/global_descriptor_table.hpp index e485d65c..986dd566 100644 --- a/arch/x86_64/arch/cpu/global_descriptor_table.hpp +++ b/arch/x86_64/arch/cpu/global_descriptor_table.hpp @@ -23,7 +23,7 @@ namespace arch::cpu { template global_descriptor_table_pointer(global_descriptor_table const & gdt) - : size{GdtSize * sizeof(segment_descriptor) - 1} + : size{GdtSize - 1} , address{kapi::memory::physical_address{std::bit_cast(&gdt)}.raw()} {} -- cgit v1.2.3 From 041ae23d5d952f134533443b508b1287af2357d3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 3 Sep 2026 21:05:48 +0200 Subject: x86_64/cpu: reload the task register When execution enters the kernel, no specific task register state has been established, leaving the power-on state of the CPU itself active. We have no control over that state, ergo we need to reload the task register to point to descriptor under our control. The earliest point when we can do that is after the new global descriptor table has been loaded. Thus this is the exact point where we do that. Additionally, reloading the TR has unveiled another latent bug that was present since the early days of the CPU initialization code: The TSS descriptor was actually incorrect. The reason for this not having been revealed earlier, is that the CPU was quietly using the TR set up by by its own power-on bootstrap. Once a load with the existing, non-TSS, descriptor was issued, A #GP was triggered because the CPU detected that the referenced TSS descriptor is not in fact a TSS descriptor (subtype 0x9): ----- BEGIN EXCEPTION DUMP ----- check_exception old: 0xffffffff new 0xd 0: v=0d e=0028 i=0 cpl=0 IP=0008:ffffffff80281b12 pc=ffffffff80281b12 SP=0010:ffffffff80216390 env->regs[R_EAX]=0000000000000028 RAX=0000000000000028 RBX=0000000000000000 RCX=ffffffff80216100 RDX=ffffffff8010fca0 RSI=0000000000000050 RDI=ffffffff80216260 RBP=ffffffff802163d0 RSP=ffffffff80216390 R8 =ffffffff802160f7 R9 =ffffffff80115328 R10=ffffffff8021626c R11=0000000000000000 R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000 RIP=ffffffff80281b12 RFL=00000092 [--S-A--] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA] CS =0008 0000000000000000 ffffffff 00af9800 DPL=0 CS64 [---] SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA] DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA] FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA] GS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA] LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy GDT= ffffffff801154e0 000001bf IDT= 0000000000000000 00000000 CR0=80000013 CR2=0000000000000000 CR3=0000000000102000 CR4=00000620 DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 DR6=00000000ffff0ff0 DR7=0000000000000400 CCS=0000000000000090 CCD=ffffffff802161f8 CCO=EFLAGS EFER=0000000000000500 ----- END EXCEPTION DUMP ----- Decoding the e= value of the exception shows that the #GP occurred while the CPU was trying to process index 5 of the GDT (bits 3-15 define the index, with e=0028 being 0000'0000'0010'1000 => index 5). The layout of a system segment descriptor differs from a normal segment descriptor in that the accessed, read/write, conforming, and executable bits change their meaning into a 4-bit subtype number. For a TSS descriptor, this subtype number must be 9. In the future, the data structures of the GDT implementation should be revised to ensure this kind of misconfiguration can not happen again. --- arch/x86_64/arch/cpu/initialization.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/arch/cpu/initialization.cpp b/arch/x86_64/arch/cpu/initialization.cpp index 83493fe3..67bc2a4d 100644 --- a/arch/x86_64/arch/cpu/initialization.cpp +++ b/arch/x86_64/arch/cpu/initialization.cpp @@ -95,10 +95,10 @@ namespace arch::cpu { .limit_low = limit & 0xffff, // NOLINT(readability-magic-numbers) .base_low = address & 0xffffff, // NOLINT(readability-magic-numbers) - .accessed = false, + .accessed = true, .read_write = false, .direction_or_conforming = false, - .executable = false, + .executable = true, .type = segment_type::system, .privilege_level = 0, .present = true, @@ -126,6 +126,10 @@ namespace arch::cpu kstd::println("[ARCH:SYS] Reloading Global Descriptor Table."); gdt.load(1, 2); + kstd::println("[ARCH:SYS] Loading the Task Register."); + auto const tss_selector_offset = static_cast(5 * sizeof(segment_descriptor)); + asm volatile("ltr %0" : : "r"(tss_selector_offset)); + kstd::println("[ARCH:SYS] Initializing Interrupt Descriptor Table."); auto static idt = interrupt_descriptor_table{}; idt.load(); -- cgit v1.2.3 From aee4582fb5144e1dd493041a8d1fc0c08146a622 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 18:14:16 +0200 Subject: x86_64/cpu: isolate kernel and IST1 stack Previously, the kernel stack was allocated inside the .kernel_bss section, along other uninitialized data. While this works, it assumes that the section will always be laid out with the kernel stack at the top. If that is not the case, the allocated guard page before .kernel_bss would not trigger a #PF since out-of-bounds (overflow) access would quietly overwrite other data in the section, thus potentially corrupting global kernel data. At the same time, there was no separate section (and guard page) for the future #DF exception stack (IST1 in our case). Thus we allocate a section, and a guard page, while we are already modifying the linker script. --- arch/x86_64/scripts/kernel.ld | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index e6ae3425..8cd6c1c3 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -98,9 +98,21 @@ SECTIONS . += 4K; + .kernel_stack ALIGN(4K) : AT (ADDR (.kernel_stack) - TEACHOS_VMA) + { + *(.stack) + } :kernel_data + + . += 4K; + + .kernel_ist1_stack ALIGN(4K) : AT (ADDR (.kernel_ist1_stack) - TEACHOS_VMA) + { + *(.ist1_stack) + } :kernel_data + .kernel_bss ALIGN(4K) : AT (ADDR (.kernel_bss) - TEACHOS_VMA) { - *(.stack .bss*) + *(.bss*) } :kernel_data .kernel_text ALIGN(4K) : AT(ADDR (.kernel_text) - TEACHOS_VMA) -- cgit v1.2.3 From a5848c037e6e681d586312ddddddd200b9f7a5b0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 20:24:06 +0200 Subject: x86_64/cpu: use IST1 as the stack for #DF --- arch/x86_64/arch/cpu/initialization.cpp | 20 +++++++++++++++++++- arch/x86_64/arch/cpu/interrupts.cpp | 4 +++- arch/x86_64/arch/cpu/task_state_segment.hpp | 21 +++++++++++---------- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/arch/cpu/initialization.cpp b/arch/x86_64/arch/cpu/initialization.cpp index 67bc2a4d..be1cc9f8 100644 --- a/arch/x86_64/arch/cpu/initialization.cpp +++ b/arch/x86_64/arch/cpu/initialization.cpp @@ -8,7 +8,9 @@ #include +#include #include +#include #include namespace arch::cpu @@ -111,11 +113,27 @@ namespace arch::cpu (address >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) }; } + + [[gnu::section(".ist1_stack")]] auto constinit ist1_stack = std::array{}; + + auto constinit tss = task_state_segment{ + .rsp0 = nullptr, + .rsp1 = nullptr, + .rsp2 = nullptr, + .ist1 = ist1_stack.data() + ist1_stack.size(), + .ist2 = nullptr, + .ist3 = nullptr, + .ist4 = nullptr, + .ist5 = nullptr, + .ist6 = nullptr, + .ist7 = nullptr, + .io_map_base_address = 0, + }; + } // namespace auto initialize_descriptors() -> void { - auto static tss = task_state_segment{}; auto static tss_descriptor = make_tss_descriptor(&tss); auto static gdt = global_descriptor_table{ diff --git a/arch/x86_64/arch/cpu/interrupts.cpp b/arch/x86_64/arch/cpu/interrupts.cpp index 2fdc4671..cf225a90 100644 --- a/arch/x86_64/arch/cpu/interrupts.cpp +++ b/arch/x86_64/arch/cpu/interrupts.cpp @@ -167,10 +167,12 @@ namespace arch::cpu { for (auto i = 0uz; i < 256; ++i) { + auto ist_selector = static_cast(i == 8 ? 1 : 0); + m_descriptors[i] = gate_descriptor{ .offset_low = static_cast(isr_stub_table[i] & 0xffff), // NOLINT(readability-magic-numbers) .m_code_segment = segment_selector{0, false, 1}, - .interrupt_stack_table_selector = 0, + .interrupt_stack_table_selector = ist_selector, .gate_type = (i < 32 && i != 2) ? gate_type::trap_gate : gate_type::interrupt_gate, .descriptor_privilege_level = 0, .present = true, diff --git a/arch/x86_64/arch/cpu/task_state_segment.hpp b/arch/x86_64/arch/cpu/task_state_segment.hpp index ab141f4c..f8b257d4 100644 --- a/arch/x86_64/arch/cpu/task_state_segment.hpp +++ b/arch/x86_64/arch/cpu/task_state_segment.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_TASK_STATE_SEGMENT_HPP #define TEACHOS_ARCH_X86_64_TASK_STATE_SEGMENT_HPP +#include #include namespace arch::cpu @@ -9,17 +10,17 @@ namespace arch::cpu struct [[gnu::packed]] task_state_segment { std::uint32_t : 32; - std::uint64_t rsp0 = {}; - std::uint64_t rsp1 = {}; - std::uint64_t rsp2 = {}; + std::byte * rsp0 = {}; + std::byte * rsp1 = {}; + std::byte * rsp2 = {}; std::uint64_t : 64; - std::uint64_t ist1 = {}; - std::uint64_t ist2 = {}; - std::uint64_t ist3 = {}; - std::uint64_t ist4 = {}; - std::uint64_t ist5 = {}; - std::uint64_t ist6 = {}; - std::uint64_t ist7 = {}; + std::byte * ist1 = {}; + std::byte * ist2 = {}; + std::byte * ist3 = {}; + std::byte * ist4 = {}; + std::byte * ist5 = {}; + std::byte * ist6 = {}; + std::byte * ist7 = {}; std::uint64_t : 64; std::uint16_t : 16; std::uint16_t io_map_base_address = {}; -- cgit v1.2.3 From f00223b5cc99a8f3f1b6a15658d8c854c177932a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 20:25:14 +0200 Subject: x86_64/cpu: handle #DF inside the arch code A double fault is a very x86-64 specific type of exception and not recoverable in a generalized way. Thus we should handle it internally, with handling currently being triggering a panic, and not forward it to the architecture-independent kernel layer. --- arch/x86_64/arch/cpu/interrupts.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/arch/cpu/interrupts.cpp b/arch/x86_64/arch/cpu/interrupts.cpp index cf225a90..94806621 100644 --- a/arch/x86_64/arch/cpu/interrupts.cpp +++ b/arch/x86_64/arch/cpu/interrupts.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -124,6 +125,12 @@ namespace arch::cpu } pic_master_control_port::write(pic_end_of_interrupt); } + + auto handle_double_fault(interrupt_frame * frame) -> void + { + kapi::system::panic("[ARCH:CPU] Double fault! Possible kernel stack corruption! rsp was {}", + frame->cpu_saved.rsp); + } } // namespace extern "C" @@ -134,7 +141,11 @@ namespace arch::cpu { auto [number, code] = frame->interrupt; - if (number < number_of_exception_vectors) + if (number == static_cast(exception::double_fault)) + { + handle_double_fault(frame); + } + else if (number < number_of_exception_vectors) { if (!dispatch_exception(frame)) { -- cgit v1.2.3 From c6d5c461ff8ec1d8361c477a4318491755a24235 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 21:04:24 +0200 Subject: x86_64/boot: reduce kernel stack size to 8 KiB --- arch/x86_64/arch/boot/entry64.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/arch/boot/entry64.s b/arch/x86_64/arch/boot/entry64.s index 29fb778d..d08276c0 100644 --- a/arch/x86_64/arch/boot/entry64.s +++ b/arch/x86_64/arch/boot/entry64.s @@ -2,7 +2,7 @@ .align 16 .global stack_top -stack_bottom: .skip 1 << 20 +stack_bottom: .skip 1 << 13 stack_top: stack_size = stack_top - stack_bottom -- cgit v1.2.3 From ccd0a1ca865d3b640f902945df84bb2be388a755 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 22:10:44 +0200 Subject: x86_64/cpu: fix asm input constraint The "X" constraint tells GCC that any operand whatsoever is valid to be placed in the assembler template. This makes no sense in this case, since that would allow for the exact expression to be inserted. If that happens, which it does when `-Og` is active, GCC is unable to assemble that template. The correct constraint is forcing the value into a register. --- arch/x86_64/arch/cpu/global_descriptor_table.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/arch/cpu/global_descriptor_table.hpp index 986dd566..0bd7677d 100644 --- a/arch/x86_64/arch/cpu/global_descriptor_table.hpp +++ b/arch/x86_64/arch/cpu/global_descriptor_table.hpp @@ -73,8 +73,8 @@ namespace arch::cpu "mov %%rax, %%fs\n" "mov %%rax, %%gs\n" : - : "X"(code_segment_index * sizeof(segment_descriptor)), - "X"(data_segment_index * sizeof(segment_descriptor)) + : "r"(code_segment_index * sizeof(segment_descriptor)), + "r"(data_segment_index * sizeof(segment_descriptor)) : "rax"); } -- cgit v1.2.3 From 29960e6df864310f20b83da596dc0210c4dd0b62 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 22:12:57 +0200 Subject: build: clean up available build types --- cmake/Platforms/x86_64.cmake | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index b17fec8e..76ba0509 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -28,14 +28,11 @@ list(JOIN CMAKE_CXX_FLAGS_INIT " " CMAKE_CXX_FLAGS_INIT) set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,--gc-sections") -set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3") -set(CMAKE_ASM_FLAGS_DEBUG "-ggdb3") +set(CMAKE_CXX_FLAGS_DEBUG "-Og -ggdb3") +set(CMAKE_ASM_FLAGS_DEBUG "-Og -ggdb3") set(CMAKE_ASM_FLAGS_MINSIZEREL "-Os -DNDEBUG -ggdb3") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -ggdb3") -set(CMAKE_ASM_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb3") -set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb3") - -set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3") +set(CMAKE_ASM_FLAGS_RELEASE "-O2 -DNDEBUG -ggdb3") +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG -ggdb3") -- cgit v1.2.3 From 0e2ddf50d85c18d7f043c15dbb56cfdbf75984bc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 22:13:23 +0200 Subject: kstd/libc: add missing undefined function Even though we implement our own `memset` function, we did not define it as undefined. This lead to undefine symbols `-O2` builds, which prefer `memset` in situation in which `-Os` builds do not. --- libs/kstd/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index a5b76a62..573fc8f2 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -58,6 +58,7 @@ if(NOT BUILD_TESTING) "strlen" "memcmp" "memcpy" + "memset" ) list(TRANSFORM KSTD_LIBC_SYMBOLS PREPEND "-Wl,--undefined=") -- cgit v1.2.3 From 9bbe812c3ccc5b26100e4fbd30b851c609e8a3a7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 22:15:01 +0200 Subject: build: use Release config for release builds --- CMakePresets.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index b26d9576..2dc18a09 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,7 +7,7 @@ "binaryDir": "${sourceDir}/build/${presetName}", "generator": "Ninja Multi-Config", "cacheVariables": { - "CMAKE_CONFIGURATION_TYPES": "Debug;MinSizeRel", + "CMAKE_CONFIGURATION_TYPES": "Debug;Release", "CMAKE_EXPORT_COMPILE_COMMANDS": true, "CMAKE_VERIFY_INTERFACE_HEADER_SETS": true } @@ -58,7 +58,7 @@ "displayName": "x86-64 kernel image (Release)", "description": "Bootable release image for x86-64 systems", "configurePreset": "x86_64", - "configuration": "MinSizeRel" + "configuration": "Release" }, { "name": "bht-dbg", @@ -72,7 +72,7 @@ "displayName": "Build-host tests (Release)", "description": "Unit and integration tests", "configurePreset": "bht", - "configuration": "MinSizeRel" + "configuration": "Release" }, { "name": "bht-stress-dbg", @@ -108,7 +108,7 @@ "displayName": "Build-host tests (Release)", "description": "Unit and integration tests", "configurePreset": "bht", - "configuration": "MinSizeRel", + "configuration": "Release", "output": { "outputOnFailure": true }, @@ -134,7 +134,7 @@ "displayName": "Build-host stress tests (Release)", "description": "Stress tests", "configurePreset": "bht-stress", - "configuration": "MinSizeRel", + "configuration": "Release", "output": { "outputOnFailure": true }, -- cgit v1.2.3 From 3697f01a3906815cbbbe8927f50045163976c1db Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 4 Sep 2026 22:15:18 +0200 Subject: build: enable stack frame size diagnostics It has been observed that certain call-chains are too large for a 4 KiB kernel stack. While we have increased the stack on x86-64 to 8 KiB, it seems desirable to enable diagnostics that warn us of large stack frames. This changeset introduces 3 new CMake configuration options, two of which are considered internal: TEACHOS_STACK_FRAME_LIMIT: The size limit of in bytes we are willing to accepts for any given stack frame. Defaults to "0", meaning the internal defaults are used per build configuration. TEACHOS_STACK_FRAME_LIMIT_DEBUG: TEACHOS_STACK_FRAME_LIMIT_RELEASE: !!internal!! The default stack frame size limit in bytes, per configuration, if no user specified stack frame size limit was defined at configure time. --- CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 830da817..34738e18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,15 @@ option(TEACHOS_ENABLE_TEST_TSAN "Enable TSan for the test executable" OFF) set(ACPI_ENABLE_TEST_COVERAGE ${TEACHOS_ENABLE_TEST_COVERAGE}) set(KSTD_ENABLE_TEST_COVERAGE ${TEACHOS_ENABLE_TEST_COVERAGE}) +set(CACHE{TEACHOS_STACK_FRAME_LIMIT} + TYPE STRING + HELP "The maximum allowed stack frame size in bytes." + VALUE "0" +) + +set(CACHE{TEACHOS_STACK_FRAME_LIMIT_DEBUG} TYPE INTERNAL VALUE "3072") +set(CACHE{TEACHOS_STACK_FRAME_LIMIT_RELEASE} TYPE INTERNAL VALUE "1280") + #[============================================================================[ # Global Build System Configuration #]============================================================================] @@ -69,6 +78,27 @@ add_compile_options( "$<$:-pedantic-errors>" ) +if(NOT BUILD_TESTING) + if(TEACHOS_STACK_FRAME_LIMIT) + set(STACK_FRAME_LIMIT "${TEACHOS_STACK_FRAME_LIMIT}") + else() + set(STACK_FRAME_LIMIT "$,${TEACHOS_STACK_FRAME_LIMIT_DEBUG},${TEACHOS_STACK_FRAME_LIMIT_RELEASE}>") + endif() + + add_compile_options( + "$<$:-fstack-usage>" + "$<$:-Wframe-larger-than=${STACK_FRAME_LIMIT}>" + ) + + add_link_options( + "$<$:-fstack-usage>" + "$<$:-Wframe-larger-than=${STACK_FRAME_LIMIT}>" + "$<$:-Werror=frame-larger-than=${STACK_FRAME_LIMIT}>" + ) + + unset(STACK_FRAME_LIMIT) +endif() + #[============================================================================[ # Global Linting Configuration #]============================================================================] -- cgit v1.2.3 From 3eb72bb6bc7446df3e34bd990cb84a0b8178b9cd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 5 Sep 2026 11:18:38 +0200 Subject: x86_64/cpu: improve stack overflow detection --- arch/x86_64/arch/cpu/interrupts.cpp | 29 +++++++++++++++++++++++++++-- arch/x86_64/scripts/kernel.ld | 2 ++ kapi/kapi/memory/address.hpp | 4 ++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/arch/cpu/interrupts.cpp b/arch/x86_64/arch/cpu/interrupts.cpp index 94806621..f27c3a2e 100644 --- a/arch/x86_64/arch/cpu/interrupts.cpp +++ b/arch/x86_64/arch/cpu/interrupts.cpp @@ -9,7 +9,9 @@ #include #include +#include +#include #include namespace arch::cpu @@ -17,6 +19,9 @@ namespace arch::cpu namespace { + extern "C" std::byte __kernel_stack_bottom[]; // NOLINT(readability-identifier-naming) + extern "C" std::byte __ist1_stack_bottom[]; // NOLINT(readability-identifier-naming) + enum struct exception { divide_error, @@ -128,8 +133,28 @@ namespace arch::cpu auto handle_double_fault(interrupt_frame * frame) -> void { - kapi::system::panic("[ARCH:CPU] Double fault! Possible kernel stack corruption! rsp was {}", - frame->cpu_saved.rsp); + auto const rsp = frame->cpu_saved.rsp; + auto const rip = frame->cpu_saved.rip; + auto const kernel_stack_bottom = kapi::memory::linear_address{__kernel_stack_bottom}; + auto const ist1_stack_bottom = kapi::memory::linear_address{__ist1_stack_bottom}; + + auto const overflowed_kernel = rsp < kernel_stack_bottom && rsp >= kernel_stack_bottom - kapi::memory::page::size; + auto const overflowed_ist1 = rsp < ist1_stack_bottom && rsp >= ist1_stack_bottom - kapi::memory::page::size; + + if (overflowed_kernel || overflowed_ist1) + { + auto const overflowed_what = overflowed_kernel ? "kernel" : "ist1"; + auto const overflowed_by = + kstd::bytes{static_cast((overflowed_kernel ? kernel_stack_bottom : ist1_stack_bottom) - rsp)}; + + kapi::system::panic("[ARCH:CPU] Suspected {} stack overflow: \n" // + "\toverflowed by: {:#}\n" // + "\trsp: {}\n" // + "\trip: {}\n", // + overflowed_what, overflowed_by, rsp, rip); + } + + kapi::system::panic("[ARCH:CPU] Double fault at {}", rip); } } // namespace diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 8cd6c1c3..f96152d7 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -100,6 +100,7 @@ SECTIONS .kernel_stack ALIGN(4K) : AT (ADDR (.kernel_stack) - TEACHOS_VMA) { + PROVIDE_HIDDEN(__kernel_stack_bottom = .); *(.stack) } :kernel_data @@ -107,6 +108,7 @@ SECTIONS .kernel_ist1_stack ALIGN(4K) : AT (ADDR (.kernel_ist1_stack) - TEACHOS_VMA) { + PROVIDE_HIDDEN(__ist1_stack_bottom = .); *(.ist1_stack) } :kernel_data diff --git a/kapi/kapi/memory/address.hpp b/kapi/kapi/memory/address.hpp index a7f5ac92..5b84a381 100644 --- a/kapi/kapi/memory/address.hpp +++ b/kapi/kapi/memory/address.hpp @@ -102,7 +102,7 @@ namespace kapi::memory //! //! @param n The amount to subtract from this address //! @return A nre address, @p n ahead of this one - [[nodiscard]] constexpr auto operator-(std::ptrdiff_t n) noexcept -> address + [[nodiscard]] constexpr auto operator-(std::ptrdiff_t n) const noexcept -> address { return address{m_value - n}; } @@ -139,7 +139,7 @@ namespace kapi::memory //! //! @param other The address to calculate the distance to. //! @return The distance between this address and the given one. - [[nodiscard]] constexpr auto operator-(address const & other) noexcept -> std::ptrdiff_t + [[nodiscard]] constexpr auto operator-(address const & other) const noexcept -> std::ptrdiff_t { return m_value - other.m_value; } -- cgit v1.2.3 From c0b2173d6b6c4587d1df3e8ea992ee19c9ff4418 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 5 Sep 2026 11:27:44 +0200 Subject: x86_64: stop loading uninitialized data --- arch/x86_64/scripts/kernel.ld | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index f96152d7..3b2fd898 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -52,7 +52,7 @@ SECTIONS PROVIDE_HIDDEN(__init_array_end = .); } :boot_data - .boot_bss ALIGN(4K) : + .boot_bss ALIGN(4K) (NOLOAD) : { KEEP(*(.boot_stack .boot_bss*)) } :boot_data @@ -98,7 +98,7 @@ SECTIONS . += 4K; - .kernel_stack ALIGN(4K) : AT (ADDR (.kernel_stack) - TEACHOS_VMA) + .kernel_stack ALIGN(4K) (NOLOAD) : AT (ADDR (.kernel_stack) - TEACHOS_VMA) { PROVIDE_HIDDEN(__kernel_stack_bottom = .); *(.stack) @@ -106,13 +106,13 @@ SECTIONS . += 4K; - .kernel_ist1_stack ALIGN(4K) : AT (ADDR (.kernel_ist1_stack) - TEACHOS_VMA) + .kernel_ist1_stack ALIGN(4K) (NOLOAD) : AT (ADDR (.kernel_ist1_stack) - TEACHOS_VMA) { PROVIDE_HIDDEN(__ist1_stack_bottom = .); *(.ist1_stack) } :kernel_data - .kernel_bss ALIGN(4K) : AT (ADDR (.kernel_bss) - TEACHOS_VMA) + .kernel_bss ALIGN(4K) (NOLOAD) : AT (ADDR (.kernel_bss) - TEACHOS_VMA) { *(.bss*) } :kernel_data @@ -138,7 +138,7 @@ SECTIONS . += 4K; - .user_bss ALIGN(4K) : AT(ADDR (.user_bss) - TEACHOS_VMA) + .user_bss ALIGN(4K) (NOLOAD) : AT(ADDR (.user_bss) - TEACHOS_VMA) { KEEP(*(.user_bss*)) } :user_data -- cgit v1.2.3 From 9f544dea5dbcdb92f614c6092a60e81d3398b8da Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 5 Sep 2026 13:19:25 +0200 Subject: build: enable strong stack protector --- CMakeLists.txt | 1 + arch/x86_64/arch/boot/initialize_runtime.cpp | 11 +++++++++++ libs/kstd/CMakeLists.txt | 2 ++ 3 files changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34738e18..8f622050 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ add_compile_options( "$<$:-Wextra>" "$<$:-Werror>" "$<$:-pedantic-errors>" + "$<$:-fstack-protector-strong>" ) if(NOT BUILD_TESTING) diff --git a/arch/x86_64/arch/boot/initialize_runtime.cpp b/arch/x86_64/arch/boot/initialize_runtime.cpp index e548f4a1..ad2fa205 100644 --- a/arch/x86_64/arch/boot/initialize_runtime.cpp +++ b/arch/x86_64/arch/boot/initialize_runtime.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -12,6 +14,15 @@ namespace arch::boot // NOLINTBEGIN(readability-identifier-naming) extern global_initializer __init_array_start; extern global_initializer __init_array_end; + + [[gnu::used]] + constinit auto __stack_chk_guard = 0xcafe'face'1ee7'8ee7; // NOLINT(readability-magic-numbers) + + [[noreturn]] + auto __stack_chk_fail() -> void + { + kapi::system::panic("Stack smashing detected!"); + } // NOLINTEND(readability-identifier-naming) auto invoke_global_constructors() -> void diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 573fc8f2..1902d0d9 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -59,6 +59,8 @@ if(NOT BUILD_TESTING) "memcmp" "memcpy" "memset" + "__stack_chk_fail" + "__stack_chk_guard" ) list(TRANSFORM KSTD_LIBC_SYMBOLS PREPEND "-Wl,--undefined=") -- cgit v1.2.3 From ebed4746799df1b733a554d0dc174307029d0196 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 9 Sep 2026 12:39:06 +0200 Subject: build: clean up presets --- CMakePresets.json | 126 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 29 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 2dc18a09..1db75229 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -24,7 +24,7 @@ }, { "name": "bht", - "displayName": "Build-host testing", + "displayName": "Build-host tests", "inherits": "base", "description": "Unit and integration tests w/ UB Sanitizer, Memory Sanitizer, and Leak Sanitizer", "cacheVariables": { @@ -35,7 +35,7 @@ }, { "name": "bht-stress", - "displayName": "Build-host stress testing", + "displayName": "Build-host stress tests", "inherits": "bht", "description": "Stress tests w/ Thread Sanitizer", "cacheVariables": { @@ -48,54 +48,59 @@ "buildPresets": [ { "name": "x86_64-dbg", - "displayName": "x86-64 kernel image (Debug)", + "displayName": "Debug Image", "description": "Bootable debug image for x86-64 systems", "configurePreset": "x86_64", "configuration": "Debug" }, { "name": "x86_64-rel", - "displayName": "x86-64 kernel image (Release)", + "displayName": "Release Image", "description": "Bootable release image for x86-64 systems", "configurePreset": "x86_64", "configuration": "Release" }, { "name": "bht-dbg", - "displayName": "Build-host tests (Debug)", + "displayName": "Debug", "description": "Unit and integration tests", "configurePreset": "bht", "configuration": "Debug" }, { "name": "bht-rel", - "displayName": "Build-host tests (Release)", + "displayName": "Release", "description": "Unit and integration tests", "configurePreset": "bht", "configuration": "Release" }, { "name": "bht-stress-dbg", - "displayName": "Build-host stress tests (Debug)", + "displayName": "Debug", "description": "Stress tests", "configurePreset": "bht-stress", "configuration": "Debug" }, { "name": "bht-stress-rel", - "displayName": "Build-host stress tests (Release)", + "displayName": "Release", "description": "Stress tests", "configurePreset": "bht-stress", - "configuration": "Debug" + "configuration": "Release" } ], "testPresets": [ { "name": "bht-dbg", - "displayName": "Build-host tests (Debug)", + "displayName": "All Tests", "description": "Unit and integration tests", "configurePreset": "bht", "configuration": "Debug", + "condition": { + "type": "equals", + "lhs": "${presetName}", + "rhs": "bht-dbg" + }, "output": { "outputOnFailure": true }, @@ -105,10 +110,15 @@ }, { "name": "bht-rel", - "displayName": "Build-host tests (Release)", + "displayName": "All Tests", "description": "Unit and integration tests", "configurePreset": "bht", "configuration": "Release", + "condition": { + "type": "equals", + "lhs": "${presetName}", + "rhs": "bht-rel" + }, "output": { "outputOnFailure": true }, @@ -118,10 +128,15 @@ }, { "name": "bht-stress-dbg", - "displayName": "Build-host stress tests (Debug)", + "displayName": "All Tests", "description": "Stress tests", "configurePreset": "bht-stress", "configuration": "Debug", + "condition": { + "type": "equals", + "lhs": "${presetName}", + "rhs": "bht-stress-dbg" + }, "output": { "outputOnFailure": true }, @@ -131,10 +146,15 @@ }, { "name": "bht-stress-rel", - "displayName": "Build-host stress tests (Release)", + "displayName": "All Tests", "description": "Stress tests", "configurePreset": "bht-stress", "configuration": "Release", + "condition": { + "type": "equals", + "lhs": "${presetName}", + "rhs": "bht-stress-rel" + }, "output": { "outputOnFailure": true }, @@ -149,8 +169,14 @@ "displayName": "x86-64 kernel (Debug)", "description": "TeachOS on x86-64", "steps": [ - { "type": "configure", "name": "x86_64" }, - { "type": "build", "name": "x86_64-dbg" } + { + "type": "configure", + "name": "x86_64" + }, + { + "type": "build", + "name": "x86_64-dbg" + } ] }, { @@ -158,8 +184,14 @@ "displayName": "x86-64 kernel (Release)", "description": "TeachOS on x86-64", "steps": [ - { "type": "configure", "name": "x86_64" }, - { "type": "build", "name": "x86_64-rel" } + { + "type": "configure", + "name": "x86_64" + }, + { + "type": "build", + "name": "x86_64-rel" + } ] }, { @@ -167,9 +199,18 @@ "displayName": "Build-host tests (Debug)", "description": "Unit and integration tests", "steps": [ - { "type": "configure", "name": "bht" }, - { "type": "build", "name": "bht-dbg" }, - { "type": "test", "name": "bht-dbg" } + { + "type": "configure", + "name": "bht" + }, + { + "type": "build", + "name": "bht-dbg" + }, + { + "type": "test", + "name": "bht-dbg" + } ] }, { @@ -177,9 +218,18 @@ "displayName": "Build-host tests (Release)", "description": "Unit and integration tests", "steps": [ - { "type": "configure", "name": "bht" }, - { "type": "build", "name": "bht-rel" }, - { "type": "test", "name": "bht-rel" } + { + "type": "configure", + "name": "bht" + }, + { + "type": "build", + "name": "bht-rel" + }, + { + "type": "test", + "name": "bht-rel" + } ] }, { @@ -187,9 +237,18 @@ "displayName": "Build-host stress tests (Debug)", "description": "Stress tests", "steps": [ - { "type": "configure", "name": "bht-stress" }, - { "type": "build", "name": "bht-stress-dbg" }, - { "type": "test", "name": "bht-stress-dbg" } + { + "type": "configure", + "name": "bht-stress" + }, + { + "type": "build", + "name": "bht-stress-dbg" + }, + { + "type": "test", + "name": "bht-stress-dbg" + } ] }, { @@ -197,9 +256,18 @@ "displayName": "Build-host stress tests (Release)", "description": "Stress tests", "steps": [ - { "type": "configure", "name": "bht-stress" }, - { "type": "build", "name": "bht-stress-rel" }, - { "type": "test", "name": "bht-stress-rel" } + { + "type": "configure", + "name": "bht-stress" + }, + { + "type": "build", + "name": "bht-stress-rel" + }, + { + "type": "test", + "name": "bht-stress-rel" + } ] } ] -- cgit v1.2.3 From c843e6a95e198aa7ace073924ff402ce0582e649 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 9 Sep 2026 12:44:18 +0200 Subject: ide: limit test executable search pattern --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index ed2b8e3b..60051580 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,6 +53,7 @@ "enabled": true, "logpanel": true }, + "testMate.cpp.test.executables": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/**/*_tests", "python-envs.defaultEnvManager": "ms-python.python:poetry", "python-envs.defaultPackageManager": "ms-python.python:poetry" } \ No newline at end of file -- cgit v1.2.3 From 010c669462c64e884e1b181b4fc40132a92d7f71 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 9 Sep 2026 12:53:26 +0200 Subject: ide: clean up cmake status bar --- .vscode/settings.json | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 60051580..f105329a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,34 @@ { "cmake.useCMakePresets": "always", - "cmake.options.statusBarVisibility": "visible", + "cmake.options.statusBarVisibility": "hidden", "cmake.ctest.testExplorerIntegrationEnabled": false, "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", + "cmake.options.advanced": { + "build": { + "statusBarVisibility": "icon", + }, + "buildPreset": { + "statusBarVisibility": "visible" + }, + "configurePreset": { + "statusBarVisibility": "visible" + }, + "testPreset": { + "statusBarVisibility": "visible" + }, + "ctest": { + "statusBarVisibility": "icon" + }, + "launch": { + "statusBarVisibility": "hidden", + }, + "debug": { + "statusBarVisibility": "hidden", + }, + "launchTarget": { + "statusBarVisibility": "hidden", + } + }, "clangd.arguments": [ "--compile-commands-dir=${workspaceFolder}/build", "--query-driver=**/x86_64-pc-elf-g++", -- cgit v1.2.3 From 9438d08cc7a7f814d8d1b0cb13f4db176fc53aeb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 9 Sep 2026 17:35:02 +0200 Subject: kstd/fmt: remove superfluous specifiers member --- libs/kstd/kstd/bits/format/formatter/char.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libs/kstd/kstd/bits/format/formatter/char.hpp b/libs/kstd/kstd/bits/format/formatter/char.hpp index 92489a1e..f7e48b49 100644 --- a/libs/kstd/kstd/bits/format/formatter/char.hpp +++ b/libs/kstd/kstd/bits/format/formatter/char.hpp @@ -16,8 +16,6 @@ namespace kstd template<> struct formatter : formatter { - bits::format::specifiers specifiers{}; - constexpr auto parse(format_parse_context & context) -> format_parse_context::iterator { specifiers = bits::format::parse_format_specifiers(context); -- cgit v1.2.3 From b99b79d8080cc1491f96069677d9ce0b7775a4f0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 9 Sep 2026 23:02:20 +0200 Subject: chore: replace some naked pointers The coding guidelines explicitly prohibit the use of "naked"/C-style pointers. However, there were some prominent examples in the kapi and the core kernel source. This changeset replaces them with the appropriate smart pointer types. --- CONTRIBUTING.rst | 2 +- arch/x86_64/arch/devices/cpu/core.cpp | 5 ++-- arch/x86_64/arch/devices/cpu/core.hpp | 4 ++- arch/x86_64/arch/devices/cpu/lapic.cpp | 5 ++-- arch/x86_64/arch/devices/cpu/lapic.hpp | 4 ++- arch/x86_64/arch/devices/pit.cpp | 6 +++-- arch/x86_64/arch/devices/pit.hpp | 4 ++- arch/x86_64/arch/drivers/cpu/lapic.cpp | 10 ++++---- arch/x86_64/arch/drivers/cpu/lapic.hpp | 3 ++- arch/x86_64/arch/drivers/pit.cpp | 4 +-- arch/x86_64/arch/drivers/pit.hpp | 2 +- .../tb0003-facet-based-capability-dispatch.rst | 26 +++++++++---------- docs/guides/device-drivers.rst | 6 ++--- kapi/kapi/boot_modules/device.hpp | 4 ++- kapi/kapi/devices.hpp | 4 +-- kapi/kapi/devices/bus.hpp | 2 +- kapi/kapi/devices/device.hpp | 16 ++++++------ kapi/kapi/devices/driver.hpp | 12 +++++---- kapi/kapi/devices/facet_registry.hpp | 30 +++++++++++----------- kernel/kapi/boot_modules/device.cpp | 5 ++-- kernel/kapi/devices/bus.cpp | 6 ++--- kernel/kapi/devices/device.cpp | 10 ++++---- kernel/kapi/devices/driver.cpp | 3 ++- kernel/kapi/devices/driver.tests.cpp | 29 +++++++++++---------- kernel/kapi/devices/driver_registry.tests.cpp | 12 ++++----- kernel/kapi/devices/facet_registry.cpp | 6 ++--- kernel/kapi/devices/facet_registry.tests.cpp | 10 ++++---- kernel/kernel/devices/pseudo.cpp | 5 ++-- kernel/kernel/devices/pseudo.hpp | 3 ++- kernel/kernel/drivers/pseudo/null.cpp | 6 ++--- kernel/kernel/drivers/pseudo/null.hpp | 3 ++- kernel/kernel/drivers/pseudo/zero.cpp | 6 ++--- kernel/kernel/drivers/pseudo/zero.hpp | 3 ++- kernel/kernel/drivers/storage/ram_disk.cpp | 10 ++++---- kernel/kernel/drivers/storage/ram_disk.hpp | 3 ++- .../kernel/test_support/devices/block_device.cpp | 5 ++-- .../kernel/test_support/devices/block_device.hpp | 3 ++- kernel/kernel/vfs/device_inode.cpp | 4 +-- 38 files changed, 153 insertions(+), 128 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 97028855..2dbd613c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -559,7 +559,7 @@ See the following code snippet for examples: .. code-block:: cpp [[nodiscard]] auto children() const -> kstd::vector>; - [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> void *; + [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> kstd::observer_ptr; [[nodiscard]] auto request_resource(resource_type type, std::size_t index = 0) const -> kstd::result; ``constexpr`` and ``constinit`` diff --git a/arch/x86_64/arch/devices/cpu/core.cpp b/arch/x86_64/arch/devices/cpu/core.cpp index ac06850e..13d4652d 100644 --- a/arch/x86_64/arch/devices/cpu/core.cpp +++ b/arch/x86_64/arch/devices/cpu/core.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -29,11 +30,11 @@ namespace arch::devices::cpu return m_id; } - auto core::query_facet(kapi::capabilities::facet_id facet) -> void * + auto core::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == bus::core_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return device::query_facet(facet); diff --git a/arch/x86_64/arch/devices/cpu/core.hpp b/arch/x86_64/arch/devices/cpu/core.hpp index cd5ac65c..ad965da1 100644 --- a/arch/x86_64/arch/devices/cpu/core.hpp +++ b/arch/x86_64/arch/devices/cpu/core.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -20,7 +22,7 @@ namespace arch::devices::cpu [[nodiscard]] auto hardware_id() const noexcept -> std::uint64_t override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: std::uint64_t m_id; diff --git a/arch/x86_64/arch/devices/cpu/lapic.cpp b/arch/x86_64/arch/devices/cpu/lapic.cpp index 280ebbca..d8571a8f 100644 --- a/arch/x86_64/arch/devices/cpu/lapic.cpp +++ b/arch/x86_64/arch/devices/cpu/lapic.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -29,11 +30,11 @@ namespace arch::devices::cpu return m_is_bsp; } - auto lapic::query_facet(kapi::capabilities::facet_id facet) -> void * + auto lapic::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == bus::lapic_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return device::query_facet(facet); diff --git a/arch/x86_64/arch/devices/cpu/lapic.hpp b/arch/x86_64/arch/devices/cpu/lapic.hpp index 52ae40ae..3f91968e 100644 --- a/arch/x86_64/arch/devices/cpu/lapic.hpp +++ b/arch/x86_64/arch/devices/cpu/lapic.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -20,7 +22,7 @@ namespace arch::devices::cpu [[nodiscard]] auto is_bsp() const noexcept -> bool override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: std::uint64_t m_id; diff --git a/arch/x86_64/arch/devices/pit.cpp b/arch/x86_64/arch/devices/pit.cpp index 83443c93..6de23865 100644 --- a/arch/x86_64/arch/devices/pit.cpp +++ b/arch/x86_64/arch/devices/pit.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include namespace arch::devices @@ -19,11 +21,11 @@ namespace arch::devices return "pit"; } - auto pit::query_facet(kapi::capabilities::facet_id facet) -> void * + auto pit::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == arch::bus::isa_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::device::query_facet(facet); diff --git a/arch/x86_64/arch/devices/pit.hpp b/arch/x86_64/arch/devices/pit.hpp index 08bf423a..ddd6d8a3 100644 --- a/arch/x86_64/arch/devices/pit.hpp +++ b/arch/x86_64/arch/devices/pit.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include namespace arch::devices @@ -25,7 +27,7 @@ namespace arch::devices [[nodiscard]] auto isa_name() const -> std::string_view override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; }; } // namespace arch::devices diff --git a/arch/x86_64/arch/drivers/cpu/lapic.cpp b/arch/x86_64/arch/drivers/cpu/lapic.cpp index c02c3df6..3b7c2d45 100644 --- a/arch/x86_64/arch/drivers/cpu/lapic.cpp +++ b/arch/x86_64/arch/drivers/cpu/lapic.cpp @@ -104,7 +104,7 @@ namespace arch::drivers::cpu auto lapic::probe(kapi::devices::device & device) -> kstd::result { - auto * signature = device.facet(); + auto const signature = device.facet(); if (!signature) { return kstd::failure(make_error_code(kstd::errc::invalid_argument)); @@ -142,8 +142,8 @@ namespace arch::drivers::cpu write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); - kstd::println("[ARCH:DRV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", - version, highest_lvt_entry_index, supports_eoi_broadcast_suppression); + kstd::println("[ARCH:DRV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", version, + highest_lvt_entry_index, supports_eoi_broadcast_suppression); } else { @@ -172,11 +172,11 @@ namespace arch::drivers::cpu *reg = value; } - auto lapic::query_facet(kapi::capabilities::facet_id facet) -> void * + auto lapic::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == arch::bus::lapic_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); diff --git a/arch/x86_64/arch/drivers/cpu/lapic.hpp b/arch/x86_64/arch/drivers/cpu/lapic.hpp index 678d364a..52533d9a 100644 --- a/arch/x86_64/arch/drivers/cpu/lapic.hpp +++ b/arch/x86_64/arch/drivers/cpu/lapic.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -27,7 +28,7 @@ namespace arch::drivers::cpu [[nodiscard]] auto name() const noexcept -> std::string_view override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: enum struct registers : std::ptrdiff_t; diff --git a/arch/x86_64/arch/drivers/pit.cpp b/arch/x86_64/arch/drivers/pit.cpp index e6e98796..6a768fc9 100644 --- a/arch/x86_64/arch/drivers/pit.cpp +++ b/arch/x86_64/arch/drivers/pit.cpp @@ -124,11 +124,11 @@ namespace arch::drivers return kapi::interrupts::status::handled; } - auto pit::query_facet(kapi::capabilities::facet_id facet) -> void * + auto pit::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == arch::bus::isa_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); diff --git a/arch/x86_64/arch/drivers/pit.hpp b/arch/x86_64/arch/drivers/pit.hpp index ad8add4b..f5be5a17 100644 --- a/arch/x86_64/arch/drivers/pit.hpp +++ b/arch/x86_64/arch/drivers/pit.hpp @@ -33,7 +33,7 @@ namespace arch::drivers [[nodiscard]] auto name() const noexcept -> std::string_view override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: struct data diff --git a/docs/briefs/tb0003-facet-based-capability-dispatch.rst b/docs/briefs/tb0003-facet-based-capability-dispatch.rst index 2cace2f3..70d183d0 100644 --- a/docs/briefs/tb0003-facet-based-capability-dispatch.rst +++ b/docs/briefs/tb0003-facet-based-capability-dispatch.rst @@ -76,12 +76,12 @@ Querying a Single Object struct device : kstd::enable_shared_from_this { - [[nodiscard]] auto facet(kapi::capabilities::facet_id id) noexcept -> void *; + [[nodiscard]] auto facet(kapi::capabilities::facet_id id) noexcept -> kstd::observer_ptr; template [[nodiscard]] auto facet() -> FacetType * { - return static_cast(facet(FacetType::id)); + return kstd::observer_ptr{static_cast(facet(FacetType::id).get())}; } template @@ -91,7 +91,7 @@ Querying a Single Object } protected: - auto virtual query_facet(kapi::capabilities::facet_id facet) -> void *; + auto virtual query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr; }; The base implementation of ``query_facet()`` simply returns ``nullptr``. @@ -106,15 +106,15 @@ A concrete device overrides it, checks the requested id against every facet it s [[nodiscard]] auto isa_name() const -> std::string_view override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; }; // arch/x86_64/arch/devices/pit.cpp - auto pit::query_facet(kapi::capabilities::facet_id facet) -> void * + auto pit::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == arch::bus::isa_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::device::query_facet(facet); // <-- the delegation } @@ -174,10 +174,10 @@ A device is not only queried for identification facets. ``bus`` itself answers t .. code-block:: cpp // kernel/kapi/devices/bus.cpp - auto bus::query_facet(kapi::capabilities::facet_id facet) -> void * + auto bus::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { - if (facet == bus::id) { return this; } - else if (facet == bus_protocol::id) { return m_protocol; } + if (facet == bus::id) { return kstd::observer_ptr{this}; } + else if (facet == bus_protocol::id) { return kstd::observer_ptr{m_protocol}; } return device::query_facet(facet); } @@ -209,7 +209,7 @@ Everything above answers "does *this specific* device or driver support facet X" auto withdraw(device const & device, kapi::capabilities::facet_id id) -> void; [[nodiscard]] auto all(kapi::capabilities::facet_id id) const -> kstd::vector; - [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> void *; + [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> kstd::observer_ptr; auto subscribe(kstd::weak_ptr observer) -> void; // ... @@ -281,11 +281,11 @@ The two device-model facets already shown (``isa_signature``/``isa_claim``, ``bl } protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == kapi::sensors::temperature_sensor::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::device::query_facet(facet); // never forget this line } @@ -344,7 +344,7 @@ Capability query without a language-provided RTTI mechanism is a solved problem, COM's ``IUnknown::QueryInterface`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This is the closest real-world relative of facet dispatch, and almost certainly its distant conceptual ancestor. Every COM object implements ``HRESULT QueryInterface(REFIID riid, void ** ppvObject)``: given a 128-bit interface identifier (a GUID) rather than a string, it returns a pointer to that interface or an error [2]_. The shape is identical — an opaque object, a caller-supplied tag, an untyped-then-cast pointer back, no shared base class needed to know about every possible interface in advance. The differences are informative rather than superficial: COM's tags are GUIDs, generated to be globally, statistically unique, specifically to avoid the collision risk a string tag carries (see *Drawbacks*, below); ``QueryInterface`` is reference-counted (``AddRef``/``Release``) as part of the same call, because COM objects can be shared across process and apartment boundaries in ways a kernel device tree is not; and COM has a formal rule that interface identity, once shipped, can never change shape — a modified interface gets a new GUID rather than breaking existing implementers. TeachOS has no equivalent discipline yet (also noted below). +This is the closest real-world relative of facet dispatch, and almost certainly its distant conceptual ancestor. Every COM object implements ``HRESULT QueryInterface(REFIID riid, void * ppvObject)``: given a 128-bit interface identifier (a GUID) rather than a string, it returns a pointer to that interface or an error [2]_. The shape is identical — an opaque object, a caller-supplied tag, an untyped-then-cast pointer back, no shared base class needed to know about every possible interface in advance. The differences are informative rather than superficial: COM's tags are GUIDs, generated to be globally, statistically unique, specifically to avoid the collision risk a string tag carries (see *Drawbacks*, below); ``QueryInterface`` is reference-counted (``AddRef``/``Release``) as part of the same call, because COM objects can be shared across process and apartment boundaries in ways a kernel device tree is not; and COM has a formal rule that interface identity, once shipped, can never change shape — a modified interface gets a new GUID rather than breaking existing implementers. TeachOS has no equivalent discipline yet (also noted below). UEFI Protocols ~~~~~~~~~~~~~~~~ diff --git a/docs/guides/device-drivers.rst b/docs/guides/device-drivers.rst index 3d3da182..a4bfe433 100644 --- a/docs/guides/device-drivers.rst +++ b/docs/guides/device-drivers.rst @@ -143,14 +143,14 @@ TeachOS's simplest real bus, ``kernel::bus::pseudo`` (``kernel/kernel/bus/pseudo { explicit pseudo(kstd::string name); protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: pseudo_signature m_signature{*this}; }; - auto pseudo::query_facet(kapi::capabilities::facet_id facet) -> void * + auto pseudo::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { - if (facet == kernel::bus::pseudo_signature::id) { return &m_signature; } + if (facet == kernel::bus::pseudo_signature::id) { return kstd::observer_ptr{&m_signature}; } return device::query_facet(facet); } diff --git a/kapi/kapi/boot_modules/device.hpp b/kapi/kapi/boot_modules/device.hpp index 4bdd34e4..7d3e3d6e 100644 --- a/kapi/kapi/boot_modules/device.hpp +++ b/kapi/kapi/boot_modules/device.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include #include @@ -54,7 +56,7 @@ namespace kapi::boot_modules [[nodiscard]] auto module() const -> struct module const & override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: struct module m_module; diff --git a/kapi/kapi/devices.hpp b/kapi/kapi/devices.hpp index c4bda9b9..c7de1830 100644 --- a/kapi/kapi/devices.hpp +++ b/kapi/kapi/devices.hpp @@ -58,8 +58,8 @@ namespace kapi::devices //! @param name A stable name for the device. //! @param implementation The implementation of the facet for the device. template - [[nodiscard]] auto publish_facet(kstd::shared_ptr device, kstd::string name, Facet * implementation) - -> kstd::result + [[nodiscard]] auto publish_facet(kstd::shared_ptr device, kstd::string name, + kstd::observer_ptr implementation) -> kstd::result { return facet_registry::get().publish(device, std::move(name), implementation); } diff --git a/kapi/kapi/devices/bus.hpp b/kapi/kapi/devices/bus.hpp index aaca462a..476216c7 100644 --- a/kapi/kapi/devices/bus.hpp +++ b/kapi/kapi/devices/bus.hpp @@ -59,7 +59,7 @@ namespace kapi::devices protected: //! All busses have the "bus" facet. - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: auto do_remove_child(device & child) -> void; diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp index 86566bff..c3a33daf 100644 --- a/kapi/kapi/devices/device.hpp +++ b/kapi/kapi/devices/device.hpp @@ -56,22 +56,22 @@ namespace kapi::devices //! //! @param id The id of the desired facet. //! @return An opaque pointer to the facet implementation if this device supports it, nullptr otherwise. - [[nodiscard]] auto facet(kapi::capabilities::facet_id id) noexcept -> void *; + [[nodiscard]] auto facet(kapi::capabilities::facet_id id) noexcept -> kstd::observer_ptr; //! Get a specific facet of this device, if it supports it. //! //! @param id The id of the desired facet. //! @return A opaque pointer to the facet implementation if this device supports it, nullptr otherwise. - [[nodiscard]] auto facet(kapi::capabilities::facet_id id) const noexcept -> void const *; + [[nodiscard]] auto facet(kapi::capabilities::facet_id id) const noexcept -> kstd::observer_ptr; //! Get a specific facet of this device, if it supports it. //! //! @tparam FacetType The type of the desired facet. //! @return A typed pointer to the facet implementation if this device supports it, nullptr otherwise. template - [[nodiscard]] auto facet() -> FacetType * + [[nodiscard]] auto facet() -> kstd::observer_ptr { - return static_cast(facet(FacetType::id)); + return kstd::observer_ptr{static_cast(facet(FacetType::id).get())}; } //! Get a specific facet of this device, if it supports it. @@ -79,9 +79,9 @@ namespace kapi::devices //! @tparam FacetType The type of the desired facet. //! @return A typed pointer to the facet implementation if this device supports it, nullptr otherwise. template - [[nodiscard]] auto facet() const noexcept -> FacetType const * + [[nodiscard]] auto facet() const noexcept -> kstd::observer_ptr { - return static_cast(facet(FacetType::id)); + return kstd::observer_ptr{static_cast(facet(FacetType::id).get())}; } //! Check if this device has a specific facet. @@ -119,7 +119,7 @@ namespace kapi::devices auto set_state(enum state state) -> void; //! Get the driver, if any, currently bound to this device. - [[nodiscard]] auto bound_driver() const noexcept -> driver *; + [[nodiscard]] auto bound_driver() const noexcept -> kstd::shared_ptr; //! Bind this device to the given driver. auto bind_driver(kstd::weak_ptr driver) -> void; @@ -159,7 +159,7 @@ namespace kapi::devices auto set_resources(kstd::vector resources) -> void; protected: - auto virtual query_facet(kapi::capabilities::facet_id facet) -> void *; + auto virtual query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr; private: //! Busses need to be able to register themselves as a device's parent. diff --git a/kapi/kapi/devices/driver.hpp b/kapi/kapi/devices/driver.hpp index b46091fe..8c4d5e97 100644 --- a/kapi/kapi/devices/driver.hpp +++ b/kapi/kapi/devices/driver.hpp @@ -5,6 +5,7 @@ #include +#include #include #include @@ -66,9 +67,9 @@ namespace kapi::devices //! @return A pointer to this drivers implementation of the requested facet, nullptr if this driver does not //! support the requested facet. template - [[nodiscard]] auto facet() -> FacetType * + [[nodiscard]] auto facet() -> kstd::observer_ptr { - return static_cast(query_facet(FacetType::id)); + return kstd::observer_ptr{static_cast(query_facet(FacetType::id))}; } //! Retrieve this drivers implementation of a given capability facet. @@ -76,9 +77,10 @@ namespace kapi::devices //! @return A pointer to this drivers implementation of the requested facet, nullptr if this driver does not //! support the requested facet. template - [[nodiscard]] auto facet() const -> FacetType const * + [[nodiscard]] auto facet() const -> kstd::observer_ptr { - return static_cast(const_cast(this)->query_facet(FacetType::id)); + return kstd::observer_ptr{ + static_cast(const_cast(this)->query_facet(FacetType::id).get())}; } //! Check if this driver implements a given capability facet. @@ -107,7 +109,7 @@ namespace kapi::devices protected: //! Return a pointer to the implementation of the given facet if this driver supports it. - virtual auto query_facet(kapi::capabilities::facet_id facet) -> void *; + virtual auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr; }; //! @} diff --git a/kapi/kapi/devices/facet_registry.hpp b/kapi/kapi/devices/facet_registry.hpp index 3c405923..5e0367c1 100644 --- a/kapi/kapi/devices/facet_registry.hpp +++ b/kapi/kapi/devices/facet_registry.hpp @@ -51,7 +51,7 @@ namespace kapi::devices //! @param facet The id of the implemented facet. //! @param implementation A pointer to the actual implementation of the facet for the given device. constexpr entry(kstd::shared_ptr device, kstd::string name, kapi::capabilities::facet_id facet, - void * implementation) + kstd::observer_ptr implementation) : m_device{device} , m_name{name} , m_id{facet} @@ -86,7 +86,7 @@ namespace kapi::devices //! Get the facet of the device-facet-implementation tuple described by this entry. //! //! @return An untyped pointer to the facet implementation. - [[nodiscard]] constexpr auto untyped_facet() const noexcept -> void * + [[nodiscard]] constexpr auto untyped_facet() const noexcept -> kstd::observer_ptr { return m_facet; } @@ -95,11 +95,11 @@ namespace kapi::devices //! //! @return A typed pointer to the facet if the facet id matches, nullptr otherwise. template - [[nodiscard]] constexpr auto facet() noexcept -> FacetType * + [[nodiscard]] constexpr auto facet() noexcept -> kstd::observer_ptr { if (m_id == FacetType::id) { - return static_cast(untyped_facet()); + return kstd::observer_ptr{static_cast(untyped_facet().get())}; } return nullptr; } @@ -108,11 +108,11 @@ namespace kapi::devices //! //! @return A typed pointer to the facet if the facet id matches, nullptr otherwise. template - [[nodiscard]] constexpr auto facet() const noexcept -> FacetType const * + [[nodiscard]] constexpr auto facet() const noexcept -> kstd::observer_ptr { if (m_id == FacetType::id) { - return static_cast(untyped_facet()); + return kstd::observer_ptr{static_cast(untyped_facet().get())}; } return nullptr; } @@ -121,7 +121,7 @@ namespace kapi::devices kstd::weak_ptr m_device; kstd::string m_name; kapi::capabilities::facet_id m_id; - void * m_facet; + kstd::observer_ptr m_facet; }; //! Construct an empty facet registry. @@ -172,7 +172,7 @@ namespace kapi::devices //! @param name A stable name for the device. //! @param facet The implementation of the facet for the device. template - [[nodiscard]] auto publish(kstd::shared_ptr device, kstd::string name, FacetType * facet) + [[nodiscard]] auto publish(kstd::shared_ptr device, kstd::string name, kstd::observer_ptr facet) -> kstd::result { return do_publish(device, std::move(name), FacetType::id, facet); @@ -198,22 +198,22 @@ namespace kapi::devices //! //! @param id The id of the facet to look for. //! @param name The stable name of the device. - [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> void *; + [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> kstd::observer_ptr; //! Attempt to resolve a facet for a device. //! //! @param id The id of the facet to look for. //! @param device The device. - [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, device & device) -> void *; + [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, device & device) -> kstd::observer_ptr; //! Attempt to resolve a facet for a device by name. //! //! @tparam FacetType The facet to look for. //! @param name The stable name of the device. template - [[nodiscard]] auto resolve(std::string_view name) -> FacetType * + [[nodiscard]] auto resolve(std::string_view name) -> kstd::observer_ptr { - return static_cast(resolve(FacetType::id, name)); + return kstd::observer_ptr{static_cast(resolve(FacetType::id, name).get())}; } //! Attempt to resolve a facet for a device. @@ -221,9 +221,9 @@ namespace kapi::devices //! @tparam FacetType The facet to look for. //! @param device The device. template - [[nodiscard]] auto resolve(device & device) -> FacetType * + [[nodiscard]] auto resolve(device & device) -> kstd::observer_ptr { - return static_cast(resolve(FacetType::id, device)); + return kstd::observer_ptr{static_cast(resolve(FacetType::id, device).get())}; } //! Subscribe to facet publish/withdraw notifications. @@ -256,7 +256,7 @@ namespace kapi::devices //! @param id The id of the facet to be published for the device. //! @param facet The facet of the device. [[nodiscard]] auto do_publish(kstd::shared_ptr device, kstd::string name, kapi::capabilities::facet_id id, - void * facet) -> kstd::result; + kstd::observer_ptr facet) -> kstd::result; //! Notify all subscribed observers about a new facet having been published for a device. //! diff --git a/kernel/kapi/boot_modules/device.cpp b/kernel/kapi/boot_modules/device.cpp index dac24906..4bfce5f1 100644 --- a/kernel/kapi/boot_modules/device.cpp +++ b/kernel/kapi/boot_modules/device.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -27,11 +28,11 @@ namespace kapi::boot_modules return m_module; } - auto device::query_facet(kapi::capabilities::facet_id facet) -> void * + auto device::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == boot_module_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::device::query_facet(facet); diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp index 300151d5..d956c3b8 100644 --- a/kernel/kapi/devices/bus.cpp +++ b/kernel/kapi/devices/bus.cpp @@ -84,15 +84,15 @@ namespace kapi::devices return m_devices; } - auto bus::query_facet(kapi::capabilities::facet_id facet) -> void * + auto bus::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == bus::id) { - return this; + return kstd::observer_ptr(this); } else if (facet == bus_protocol::id) { - return m_protocol; + return kstd::observer_ptr{m_protocol}; } return device::query_facet(facet); diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp index 2576e20a..3a3b7cc1 100644 --- a/kernel/kapi/devices/device.cpp +++ b/kernel/kapi/devices/device.cpp @@ -23,12 +23,12 @@ namespace kapi::devices : m_name(name) {} - auto device::facet(kapi::capabilities::facet_id facet) noexcept -> void * + auto device::facet(kapi::capabilities::facet_id facet) noexcept -> kstd::observer_ptr { return query_facet(facet); } - auto device::facet(kapi::capabilities::facet_id facet) const noexcept -> void const * + auto device::facet(kapi::capabilities::facet_id facet) const noexcept -> kstd::observer_ptr { return const_cast(this)->query_facet(facet); } @@ -61,10 +61,10 @@ namespace kapi::devices m_state = state; } - auto device::bound_driver() const noexcept -> driver * + auto device::bound_driver() const noexcept -> kstd::shared_ptr { auto guard = kstd::lock_guard{m_lock}; - return m_driver.lock().get(); + return m_driver.lock(); } auto device::bind_driver(kstd::weak_ptr driver) -> void @@ -114,7 +114,7 @@ namespace kapi::devices m_resources = std::move(resources); } - auto device::query_facet(kapi::capabilities::facet_id) -> void * + auto device::query_facet(kapi::capabilities::facet_id) -> kstd::observer_ptr { return nullptr; } diff --git a/kernel/kapi/devices/driver.cpp b/kernel/kapi/devices/driver.cpp index 5ca92dc8..0f103cbc 100644 --- a/kernel/kapi/devices/driver.cpp +++ b/kernel/kapi/devices/driver.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -29,7 +30,7 @@ namespace kapi::devices return kstd::success(); } - auto driver::query_facet(kapi::capabilities::facet_id) -> void * + auto driver::query_facet(kapi::capabilities::facet_id) -> kstd::observer_ptr { return nullptr; } diff --git a/kernel/kapi/devices/driver.tests.cpp b/kernel/kapi/devices/driver.tests.cpp index ee3fe577..38d07ed9 100644 --- a/kernel/kapi/devices/driver.tests.cpp +++ b/kernel/kapi/devices/driver.tests.cpp @@ -36,8 +36,8 @@ namespace [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const -> kstd::result override { - auto const * signature = dev.facet(); - auto const * claim = drv.facet(); + auto const signature = dev.facet(); + auto const claim = drv.facet(); if (!signature || !claim || !std::ranges::contains(claim->supported_names(), signature->controller_name())) { return kstd::failure(kapi::devices::driver_match_errc::no_match); @@ -65,11 +65,11 @@ namespace } protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == controller_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::bus::query_facet(facet); } @@ -101,11 +101,11 @@ namespace } protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == leaf_signature::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::device::query_facet(facet); } @@ -123,9 +123,9 @@ namespace [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const -> kstd::result override { - auto const * ident = dev.facet(); - auto const * claims = drv.facet(); - if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->leaf_name())) + auto const signature = dev.facet(); + auto const claims = drv.facet(); + if (!signature || !claims || !std::ranges::contains(claims->supported_names(), signature->leaf_name())) { return kstd::failure(kapi::devices::driver_match_errc::no_match); } @@ -166,11 +166,11 @@ namespace } protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == controller_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); @@ -198,11 +198,11 @@ namespace } protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == leaf_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); @@ -213,7 +213,8 @@ namespace SCENARIO("a bound controller driver can attach a further, independently-typed bus protocol of its own", "[devices][driver][stacking]") { - GIVEN("a controller bus, a controller driver, and a leaf driver, none aware of each other's identification scheme") + GIVEN( + "a controller bus, a controller driver, and a leaf driver, none aware of each other's signatureification scheme") { auto outer_bus = kstd::make_shared("stacking_test_controller_bus"); diff --git a/kernel/kapi/devices/driver_registry.tests.cpp b/kernel/kapi/devices/driver_registry.tests.cpp index 02f5065f..7b08799c 100644 --- a/kernel/kapi/devices/driver_registry.tests.cpp +++ b/kernel/kapi/devices/driver_registry.tests.cpp @@ -40,7 +40,7 @@ namespace { ++*match_calls; - auto const * identification = driver.facet(); + auto const identification = driver.facet(); if (!identification) { return kstd::failure(kapi::devices::driver_match_errc::no_match); @@ -107,11 +107,11 @@ namespace mutable unsigned probe_calls; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == test_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); @@ -178,7 +178,7 @@ SCENARIO("Driver registry picks the highest-priority match", "[devices][driver_r { auto dev = kapi::devices::device_registry::get().find("driver_registry_priority_device"); REQUIRE(dev != nullptr); - REQUIRE(dev->bound_driver() == high_priority.get()); + REQUIRE(dev->bound_driver() == high_priority); } } } @@ -203,7 +203,7 @@ SCENARIO("Driver registry breaks ties by registration order", "[devices][driver_ { auto dev = kapi::devices::device_registry::get().find("driver_registry_tie_device"); REQUIRE(dev != nullptr); - REQUIRE(dev->bound_driver() == registered_first.get()); + REQUIRE(dev->bound_driver() == registered_first); } } } @@ -255,7 +255,7 @@ SCENARIO("Driver registry leaves bound driver bound, even if better driver arriv auto dev = kapi::devices::device_registry::get().find("driver_probe_failure_device"); REQUIRE(dev != nullptr); REQUIRE(dev->state() == kapi::devices::state::bound); - REQUIRE(dev->bound_driver() == lower.get()); + REQUIRE(dev->bound_driver() == lower); } } } diff --git a/kernel/kapi/devices/facet_registry.cpp b/kernel/kapi/devices/facet_registry.cpp index 2974c71e..f2f5d03b 100644 --- a/kernel/kapi/devices/facet_registry.cpp +++ b/kernel/kapi/devices/facet_registry.cpp @@ -46,7 +46,7 @@ namespace kapi::devices } auto facet_registry::do_publish(kstd::shared_ptr device, kstd::string name, kapi::capabilities::facet_id id, - void * facet) -> kstd::result + kstd::observer_ptr facet) -> kstd::result { auto published = std::optional{}; @@ -169,7 +169,7 @@ namespace kapi::devices return filtered; } - auto facet_registry::resolve(kapi::capabilities::facet_id facet, std::string_view name) -> void * + auto facet_registry::resolve(kapi::capabilities::facet_id facet, std::string_view name) -> kstd::observer_ptr { auto found_device = kstd::shared_ptr{}; { @@ -193,7 +193,7 @@ namespace kapi::devices return resolve(facet, *found_device); } - auto facet_registry::resolve(kapi::capabilities::facet_id id, device & device) -> void * + auto facet_registry::resolve(kapi::capabilities::facet_id id, device & device) -> kstd::observer_ptr { if (auto by_device = device.facet(id)) { diff --git a/kernel/kapi/devices/facet_registry.tests.cpp b/kernel/kapi/devices/facet_registry.tests.cpp index 9396fc6c..f6735f01 100644 --- a/kernel/kapi/devices/facet_registry.tests.cpp +++ b/kernel/kapi/devices/facet_registry.tests.cpp @@ -50,15 +50,15 @@ namespace return m_value; } - auto query_facet(kapi::capabilities::facet_id facet) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override { if (facet == probe_device::id) { - return static_cast(this); + return kstd::make_observer(this); } if (facet == const_device::id) { - return m_const_device; + return kstd::observer_ptr{m_const_device}; } return kapi::devices::device::query_facet(facet); @@ -143,7 +143,7 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][facet_registry]") THEN("publishing a free standing second facet for the same device succeeds") { - REQUIRE(registry.publish(device, "probe0", &free_standing_facet)); + REQUIRE(registry.publish(device, "probe0", kstd::make_observer(&free_standing_facet))); } AND_WHEN("getting all devices implementing that facet") @@ -239,7 +239,7 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][facet_registry]") THEN("publishing the facet for the device fails") { - REQUIRE_FALSE(registry.publish(device, "probe0", &facet)); + REQUIRE_FALSE(registry.publish(device, "probe0", kstd::make_observer(&facet))); } } } diff --git a/kernel/kernel/devices/pseudo.cpp b/kernel/kernel/devices/pseudo.cpp index 13a8be3d..f5ee13c3 100644 --- a/kernel/kernel/devices/pseudo.cpp +++ b/kernel/kernel/devices/pseudo.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -16,11 +17,11 @@ namespace kernel::devices : kapi::devices::device{std::move(name)} {} - auto pseudo::query_facet(kapi::capabilities::facet_id facet) -> void * + auto pseudo::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == kernel::bus::pseudo_signature::id) { - return &m_signature; + return kstd::make_observer(&m_signature); } return device::query_facet(facet); diff --git a/kernel/kernel/devices/pseudo.hpp b/kernel/kernel/devices/pseudo.hpp index efd504d5..eabe59b0 100644 --- a/kernel/kernel/devices/pseudo.hpp +++ b/kernel/kernel/devices/pseudo.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -33,7 +34,7 @@ namespace kernel::devices explicit pseudo(kstd::string name); protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; private: pseudo_signature m_signature{*this}; diff --git a/kernel/kernel/drivers/pseudo/null.cpp b/kernel/kernel/drivers/pseudo/null.cpp index 4c8bde12..9d8330b1 100644 --- a/kernel/kernel/drivers/pseudo/null.cpp +++ b/kernel/kernel/drivers/pseudo/null.cpp @@ -76,7 +76,7 @@ namespace kernel::drivers::pseudo auto implementation = kstd::make_shared(); auto published = kapi::devices::publish_facet( - device.shared_from_this(), "null", implementation.get()); + device.shared_from_this(), "null", kstd::make_observer(implementation.get())); if (!published) { @@ -117,11 +117,11 @@ namespace kernel::drivers::pseudo return names; } - auto null::query_facet(kapi::capabilities::facet_id facet) -> void * + auto null::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == kernel::bus::pseudo_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); diff --git a/kernel/kernel/drivers/pseudo/null.hpp b/kernel/kernel/drivers/pseudo/null.hpp index 6a736c33..ab8affeb 100644 --- a/kernel/kernel/drivers/pseudo/null.hpp +++ b/kernel/kernel/drivers/pseudo/null.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -36,7 +37,7 @@ namespace kernel::drivers::pseudo [[nodiscard]] auto supported_names() const noexcept -> std::span override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; }; } // namespace kernel::drivers::pseudo diff --git a/kernel/kernel/drivers/pseudo/zero.cpp b/kernel/kernel/drivers/pseudo/zero.cpp index 67ec2519..fda28d35 100644 --- a/kernel/kernel/drivers/pseudo/zero.cpp +++ b/kernel/kernel/drivers/pseudo/zero.cpp @@ -77,7 +77,7 @@ namespace kernel::drivers::pseudo auto implementation = kstd::make_shared(); auto published = kapi::devices::publish_facet( - device.shared_from_this(), "zero", implementation.get()); + device.shared_from_this(), "zero", kstd::make_observer(implementation.get())); if (!published) { @@ -118,11 +118,11 @@ namespace kernel::drivers::pseudo return names; } - auto zero::query_facet(kapi::capabilities::facet_id facet) -> void * + auto zero::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == kernel::bus::pseudo_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); diff --git a/kernel/kernel/drivers/pseudo/zero.hpp b/kernel/kernel/drivers/pseudo/zero.hpp index 7f26cc41..b5573e58 100644 --- a/kernel/kernel/drivers/pseudo/zero.hpp +++ b/kernel/kernel/drivers/pseudo/zero.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -31,7 +32,7 @@ namespace kernel::drivers::pseudo [[nodiscard]] auto supported_names() const noexcept -> std::span override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; }; } // namespace kernel::drivers::pseudo diff --git a/kernel/kernel/drivers/storage/ram_disk.cpp b/kernel/kernel/drivers/storage/ram_disk.cpp index 80f7eedc..d33b7312 100644 --- a/kernel/kernel/drivers/storage/ram_disk.cpp +++ b/kernel/kernel/drivers/storage/ram_disk.cpp @@ -118,12 +118,12 @@ namespace kernel::drivers::storage std::ranges::count_if(kapi::devices::facet_registry::get().all(kapi::filesystem::block_special_file::id), [this](auto const & published) { auto published_device = published.device(); - return published_device && published_device->bound_driver() == this; + return published_device && published_device->bound_driver().get() == this; }); auto name = kstd::format("ram{}", next_index); - auto published = kapi::devices::publish_facet(device.shared_from_this(), name, - implementation.get()); + auto published = kapi::devices::publish_facet( + device.shared_from_this(), name, kstd::make_observer(implementation.get())); if (!published) { return published; @@ -155,11 +155,11 @@ namespace kernel::drivers::storage return "Generic RAM Disk"; } - auto ram_disk::query_facet(kapi::capabilities::facet_id facet) -> void * + auto ram_disk::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == kapi::boot_modules::boot_module_claim::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::driver::query_facet(facet); diff --git a/kernel/kernel/drivers/storage/ram_disk.hpp b/kernel/kernel/drivers/storage/ram_disk.hpp index a526435b..1f7d5774 100644 --- a/kernel/kernel/drivers/storage/ram_disk.hpp +++ b/kernel/kernel/drivers/storage/ram_disk.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -28,7 +29,7 @@ namespace kernel::drivers::storage [[nodiscard]] auto name() const noexcept -> std::string_view override; protected: - auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; }; } // namespace kernel::drivers::storage diff --git a/kernel/kernel/test_support/devices/block_device.cpp b/kernel/kernel/test_support/devices/block_device.cpp index 462dc79d..fa834122 100644 --- a/kernel/kernel/test_support/devices/block_device.cpp +++ b/kernel/kernel/test_support/devices/block_device.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -68,11 +69,11 @@ namespace kernel::tests::devices return kstd::bytes{data.size()}; } - auto block_device::query_facet(kapi::capabilities::facet_id facet) -> void * + auto block_device::query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr { if (facet == kapi::filesystem::block_special_file::id) { - return static_cast(this); + return kstd::make_observer(this); } return kapi::devices::device::query_facet(facet); diff --git a/kernel/kernel/test_support/devices/block_device.hpp b/kernel/kernel/test_support/devices/block_device.hpp index 9e64ed18..94c9a58d 100644 --- a/kernel/kernel/test_support/devices/block_device.hpp +++ b/kernel/kernel/test_support/devices/block_device.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,7 @@ namespace kernel::tests::devices kstd::vector data{}; private: - [[nodiscard]] auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + [[nodiscard]] auto query_facet(kapi::capabilities::facet_id facet) -> kstd::observer_ptr override; kstd::bytes m_block_size{}; }; diff --git a/kernel/kernel/vfs/device_inode.cpp b/kernel/kernel/vfs/device_inode.cpp index e9c70f15..75ed03d6 100644 --- a/kernel/kernel/vfs/device_inode.cpp +++ b/kernel/kernel/vfs/device_inode.cpp @@ -89,12 +89,12 @@ namespace kernel::vfs auto device_inode::is_block_device() const -> bool { - return kapi::devices::facet_registry::get().resolve(*m_device); + return !!kapi::devices::facet_registry::get().resolve(*m_device); } auto device_inode::is_character_device() const -> bool { - return kapi::devices::facet_registry::get().resolve(*m_device); + return !!kapi::devices::facet_registry::get().resolve(*m_device); } auto device_inode::status() const -> kstd::result -- cgit v1.2.3