From 695dd3ce00e0831e94e70ed0d2ba5b3628fece0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Sun, 8 Jun 2025 16:32:46 +0200 Subject: [PATCH 01/11] Change workflows triggers --- .github/workflows/kanso-cd.yml | 3 +++ .github/workflows/kanso-ci.yml | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/kanso-cd.yml b/.github/workflows/kanso-cd.yml index 1f1dde4..940d863 100644 --- a/.github/workflows/kanso-cd.yml +++ b/.github/workflows/kanso-cd.yml @@ -1,5 +1,8 @@ name: Kanso-CD on: + push: + branches: + - main workflow_dispatch: jobs: diff --git a/.github/workflows/kanso-ci.yml b/.github/workflows/kanso-ci.yml index f7b2951..4825e24 100644 --- a/.github/workflows/kanso-ci.yml +++ b/.github/workflows/kanso-ci.yml @@ -1,8 +1,5 @@ name: Kanso-CI on: - push: - branches: - - main pull_request: workflow_dispatch: From 4ae8377c2b7eabefc5fab9476f19219b5eb8fa66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Sun, 8 Jun 2025 17:22:08 +0200 Subject: [PATCH 02/11] Small workflow changes --- .github/workflows/kanso-cd.yml | 6 +++--- ...-pine64_star64.yml => release-riscv64_pine64_star64.yml} | 6 +++--- .github/workflows/releases/pine64_star64/genimage.cfg | 2 +- src/Kernel/KernelMain.c | 2 +- tests/Kernel/CpuTests.c | 2 ++ 5 files changed, 10 insertions(+), 8 deletions(-) rename .github/workflows/{release-pine64_star64.yml => release-riscv64_pine64_star64.yml} (94%) diff --git a/.github/workflows/kanso-cd.yml b/.github/workflows/kanso-cd.yml index 940d863..8c82922 100644 --- a/.github/workflows/kanso-cd.yml +++ b/.github/workflows/kanso-cd.yml @@ -15,12 +15,12 @@ jobs: with: platform: ${{ matrix.Platform }} - release-pine64_star64: + release-riscv64_pine64_star64: needs: kernel-build - uses: ./.github/workflows/release-pine64_star64.yml + uses: ./.github/workflows/release-riscv64_pine64_star64.yml secrets: inherit release: - needs: release-pine64_star64 + needs: release-riscv64_pine64_star64 uses: ./.github/workflows/release.yml secrets: inherit diff --git a/.github/workflows/release-pine64_star64.yml b/.github/workflows/release-riscv64_pine64_star64.yml similarity index 94% rename from .github/workflows/release-pine64_star64.yml rename to .github/workflows/release-riscv64_pine64_star64.yml index bced922..74f6f8b 100644 --- a/.github/workflows/release-pine64_star64.yml +++ b/.github/workflows/release-riscv64_pine64_star64.yml @@ -1,4 +1,4 @@ -name: Kernel-Build +name: Release-Riscv64_Pine64_Star64 on: workflow_call: @@ -64,6 +64,6 @@ jobs: - name: Upload packaged Star64 image uses: actions/upload-artifact@v4 with: - name: kanso_pine64_star64 + name: kanso_riscv64_pine64_star64 path: | - images/kanso_pine64_star64.img + images/kanso_riscv64_pine64_star64.img diff --git a/.github/workflows/releases/pine64_star64/genimage.cfg b/.github/workflows/releases/pine64_star64/genimage.cfg index 7b14921..c9d1f6e 100644 --- a/.github/workflows/releases/pine64_star64/genimage.cfg +++ b/.github/workflows/releases/pine64_star64/genimage.cfg @@ -1,4 +1,4 @@ -image kanso_pine64_star64.img { +image kanso_riscv64_pine64_star64.img { hdimage { gpt = true } diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 630b31b..40e6956 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -34,7 +34,7 @@ void KernelMain() KernelConsolePrint(String("Kanso OS %s "), KANSO_VERSION_FULL); KernelConsolePrint(String("(%s %d-bit)\n\n"), platformInformation.Name.Pointer, platformInformation.ArchitectureBits); - //CpuSetSupervisorTrapHandler(&KernelSupervisorTrapHandler); + CpuSetSupervisorTrapHandler(&KernelSupervisorTrapHandler); BiosSetTimer(CpuReadTime() + 10000000); CpuEnableSupervisorInterrupts(CpuInterruptType_Timer); diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index a29022e..c54931b 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -35,3 +35,5 @@ Test(Cpu, CpuReadCycle) TestAssertNotEquals(0, cycle2); TestAssertGreaterThan(cycle2, cycle1); } + +// TODO: Next Supervisor trap entry From f459a7753798d5aaf6f2f514739c2c16d2844ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Tue, 10 Jun 2025 17:22:30 +0200 Subject: [PATCH 03/11] WIP Kernel Trap Handler --- src/Common/String.c | 2 +- src/Kernel/Kernel.c | 2 +- src/Kernel/KernelMain.c | 14 ++-- src/Kernel/Platform.h | 8 +-- src/Kernel/Platforms/RiscV/AsmCommon.h | 70 +++++++++++++++++++ src/Kernel/Platforms/RiscV/CMakeLists.txt | 4 +- src/Kernel/Platforms/RiscV/Cpu.c | 29 +++++--- src/Kernel/Platforms/RiscV/KernelTrapEntry.S | 32 +++++++++ .../Platforms/RiscV/SupervisorTrapEntry.S | 8 --- tests/Kernel/CpuTests.c | 20 +++++- 10 files changed, 155 insertions(+), 34 deletions(-) create mode 100644 src/Kernel/Platforms/RiscV/KernelTrapEntry.S delete mode 100644 src/Kernel/Platforms/RiscV/SupervisorTrapEntry.S diff --git a/src/Common/String.c b/src/Common/String.c index 249d514..830a9cb 100644 --- a/src/Common/String.c +++ b/src/Common/String.c @@ -103,7 +103,7 @@ void StringFormatVargs(SpanChar* destination, ReadOnlySpanChar message, va_list destination->Pointer[length++] = '0'; destination->Pointer[length++] = 'x'; - for (int64_t i = 15; i >= 0; i--) + for (int64_t i = (sizeof(uintptr_t) * 2) - 1; i >= 0; i--) { unsigned nibble = (hexaArgument >> (i * 4)) & 0xf; destination->Pointer[length++] = "0123456789abcdef"[nibble]; diff --git a/src/Kernel/Kernel.c b/src/Kernel/Kernel.c index aa3c0b1..91a155c 100644 --- a/src/Kernel/Kernel.c +++ b/src/Kernel/Kernel.c @@ -19,7 +19,7 @@ void KernelFailureCore(ReadOnlySpanChar file, uint32_t line, ReadOnlySpanChar me va_end(vargs); - CpuDisableSupervisorInterrupts(CpuInterruptType_All); + CpuDisableInterrupts(CpuInterruptType_All); while (true) { diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 40e6956..6e89a54 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -12,16 +12,14 @@ const char KernelLogo[] = ,'\0' }; -__attribute__((interrupt("supervisor"))) -__attribute__((section(".text.interrupt"))) -void KernelSupervisorTrapHandler(CpuTrapFrame* trapFrame) +void KernelTrapHandler(CpuTrapFrame* trapFrame) { auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); - CpuClearSupervisorPendingInterrupts(CpuInterruptType_Timer); - KernelConsolePrint(String("Kernel trap handler: %d (PC=%d).\n"), CpuReadTime(), programCounter); + CpuClearPendingInterrupts(CpuInterruptType_Timer); + KernelConsolePrint(String("Kernel trap handler: %d (PC=%x).\n"), CpuReadTime(), programCounter); - //CpuDisableSupervisorInterrupts(CpuInterruptType_Timer); + //CpuDisableInterrupts(CpuInterruptType_Timer); //SbiSetTimer((uint64_t)-1); BiosSetTimer(CpuReadTime() + 10000000); } @@ -34,9 +32,9 @@ void KernelMain() KernelConsolePrint(String("Kanso OS %s "), KANSO_VERSION_FULL); KernelConsolePrint(String("(%s %d-bit)\n\n"), platformInformation.Name.Pointer, platformInformation.ArchitectureBits); - CpuSetSupervisorTrapHandler(&KernelSupervisorTrapHandler); + CpuSetTrapHandler(KernelTrapHandler); BiosSetTimer(CpuReadTime() + 10000000); - CpuEnableSupervisorInterrupts(CpuInterruptType_Timer); + CpuEnableInterrupts(CpuInterruptType_Timer); while (true) { diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index 9e0b438..234a26d 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -27,10 +27,10 @@ typedef void (*CpuTrapHandler)(struct CpuTrapFrame*); uint64_t CpuReadTime(); uint64_t CpuReadCycle(); -void CpuSetSupervisorTrapHandler(CpuTrapHandler trapHandler); -void CpuEnableSupervisorInterrupts(CpuInterruptType types); -void CpuDisableSupervisorInterrupts(CpuInterruptType types); -void CpuClearSupervisorPendingInterrupts(CpuInterruptType types); +void CpuSetTrapHandler(CpuTrapHandler trapHandler); +void CpuEnableInterrupts(CpuInterruptType types); +void CpuDisableInterrupts(CpuInterruptType types); +void CpuClearPendingInterrupts(CpuInterruptType types); void CpuWaitForInterrupt(); uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame); diff --git a/src/Kernel/Platforms/RiscV/AsmCommon.h b/src/Kernel/Platforms/RiscV/AsmCommon.h index f042fc2..c4d782d 100644 --- a/src/Kernel/Platforms/RiscV/AsmCommon.h +++ b/src/Kernel/Platforms/RiscV/AsmCommon.h @@ -19,3 +19,73 @@ #endif +.macro save_general_purpose_registers + addi sp, sp, -(31 * PTR_SIZE) + save_pointer x1, 0 * PTR_SIZE(sp) + save_pointer x2, 1 * PTR_SIZE(sp) + save_pointer x3, 2 * PTR_SIZE(sp) + save_pointer x4, 3 * PTR_SIZE(sp) + save_pointer x5, 4 * PTR_SIZE(sp) + save_pointer x6, 5 * PTR_SIZE(sp) + save_pointer x7, 6 * PTR_SIZE(sp) + save_pointer x8, 7 * PTR_SIZE(sp) + save_pointer x9, 8 * PTR_SIZE(sp) + save_pointer x10, 9 * PTR_SIZE(sp) + save_pointer x11, 10 * PTR_SIZE(sp) + save_pointer x12, 11 * PTR_SIZE(sp) + save_pointer x13, 12 * PTR_SIZE(sp) + save_pointer x14, 13 * PTR_SIZE(sp) + save_pointer x15, 14 * PTR_SIZE(sp) + save_pointer x16, 15 * PTR_SIZE(sp) + save_pointer x17, 16 * PTR_SIZE(sp) + save_pointer x18, 17 * PTR_SIZE(sp) + save_pointer x19, 18 * PTR_SIZE(sp) + save_pointer x20, 19 * PTR_SIZE(sp) + save_pointer x21, 20 * PTR_SIZE(sp) + save_pointer x22, 21 * PTR_SIZE(sp) + save_pointer x23, 22 * PTR_SIZE(sp) + save_pointer x24, 23 * PTR_SIZE(sp) + save_pointer x25, 24 * PTR_SIZE(sp) + save_pointer x26, 25 * PTR_SIZE(sp) + save_pointer x27, 26 * PTR_SIZE(sp) + save_pointer x28, 27 * PTR_SIZE(sp) + save_pointer x29, 28 * PTR_SIZE(sp) + save_pointer x30, 29 * PTR_SIZE(sp) + save_pointer x31, 30 * PTR_SIZE(sp) +.endm + +.macro load_general_purpose_registers + load_pointer x1, 0 * PTR_SIZE(sp) + load_pointer x2, 1 * PTR_SIZE(sp) + load_pointer x3, 2 * PTR_SIZE(sp) + load_pointer x4, 3 * PTR_SIZE(sp) + load_pointer x5, 4 * PTR_SIZE(sp) + load_pointer x6, 5 * PTR_SIZE(sp) + load_pointer x7, 6 * PTR_SIZE(sp) + load_pointer x8, 7 * PTR_SIZE(sp) + load_pointer x9, 8 * PTR_SIZE(sp) + load_pointer x10, 9 * PTR_SIZE(sp) + load_pointer x11, 10 * PTR_SIZE(sp) + load_pointer x12, 11 * PTR_SIZE(sp) + load_pointer x13, 12 * PTR_SIZE(sp) + load_pointer x14, 13 * PTR_SIZE(sp) + load_pointer x15, 14 * PTR_SIZE(sp) + load_pointer x16, 15 * PTR_SIZE(sp) + load_pointer x17, 16 * PTR_SIZE(sp) + load_pointer x18, 17 * PTR_SIZE(sp) + load_pointer x19, 18 * PTR_SIZE(sp) + load_pointer x20, 19 * PTR_SIZE(sp) + load_pointer x21, 20 * PTR_SIZE(sp) + load_pointer x22, 21 * PTR_SIZE(sp) + load_pointer x23, 22 * PTR_SIZE(sp) + load_pointer x24, 23 * PTR_SIZE(sp) + load_pointer x25, 24 * PTR_SIZE(sp) + load_pointer x26, 25 * PTR_SIZE(sp) + load_pointer x27, 26 * PTR_SIZE(sp) + load_pointer x28, 27 * PTR_SIZE(sp) + load_pointer x29, 28 * PTR_SIZE(sp) + load_pointer x30, 29 * PTR_SIZE(sp) + load_pointer x31, 30 * PTR_SIZE(sp) + + addi sp, sp, (31 * PTR_SIZE) +.endm diff --git a/src/Kernel/Platforms/RiscV/CMakeLists.txt b/src/Kernel/Platforms/RiscV/CMakeLists.txt index 323457a..14df7dc 100644 --- a/src/Kernel/Platforms/RiscV/CMakeLists.txt +++ b/src/Kernel/Platforms/RiscV/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(Kernel UnityBuild.c Boot.S SupervisorTrapEntry.S) +add_executable(Kernel UnityBuild.c Boot.S KernelTrapEntry.S) target_link_libraries(Kernel PRIVATE Common) @@ -21,7 +21,7 @@ add_custom_command(TARGET Kernel POST_BUILD ) -add_executable(KernelTest UnityBuild.c Boot.S SupervisorTrapEntry.S) +add_executable(KernelTest UnityBuild.c Boot.S KernelTrapEntry.S) target_link_libraries(KernelTest PRIVATE Common) diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index 9e7e03d..75e8776 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -8,6 +8,8 @@ struct CpuTrapFrame extern void supervisor_trap_entry(); +CpuTrapHandler globalCpuTrapHandler; + uintptr_t ComputeCpuInterruptMask(CpuInterruptType types) { auto mask = 0; @@ -76,16 +78,25 @@ inline uint64_t CpuReadCycle() } #endif -inline void CpuSetSupervisorTrapHandler(CpuTrapHandler trapHandler) +inline void CpuSetTrapHandler(CpuTrapHandler trapHandler) { - __asm__ volatile( - "csrw stvec, %0\n" - "csrsi sstatus, 2" // TODO: Confirm the sstatus flag - : - : "r" (supervisor_trap_entry)); + globalCpuTrapHandler = trapHandler; + + if (trapHandler) + { + __asm__ volatile( + "csrw stvec, %0\n" + "csrsi sstatus, 2" + : + : "r" (supervisor_trap_entry)); + } + else + { + __asm__ volatile("csrsi sstatus, 0"); + } } -inline void CpuEnableSupervisorInterrupts(CpuInterruptType types) +inline void CpuEnableInterrupts(CpuInterruptType types) { auto mask = ComputeCpuInterruptMask(types); @@ -97,7 +108,7 @@ inline void CpuEnableSupervisorInterrupts(CpuInterruptType types) ); } -inline void CpuDisableSupervisorInterrupts(CpuInterruptType types) +inline void CpuDisableInterrupts(CpuInterruptType types) { auto mask = ComputeCpuInterruptMask(types); @@ -109,7 +120,7 @@ inline void CpuDisableSupervisorInterrupts(CpuInterruptType types) ); } -inline void CpuClearSupervisorPendingInterrupts(CpuInterruptType types) +inline void CpuClearPendingInterrupts(CpuInterruptType types) { auto mask = ComputeCpuInterruptMask(types); diff --git a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S new file mode 100644 index 0000000..d03dde5 --- /dev/null +++ b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S @@ -0,0 +1,32 @@ +#include "AsmCommon.h" + +.global supervisor_trap_entry # TODO: Rename + +.section .text.interrupt + +supervisor_trap_entry: + # TODO: We will need to do a switch later when we manage MMU + # to give the trap handler a kernel space stack independant of user mode. + # For now, we just save the current SP that is shared between kernel and user. + csrw sscratch, sp + csrr t0, sepc + + save_general_purpose_registers + # TODO: Save supervisor registers + + mv a0, sp # TODO: I don't know why we should have this one + + la t1, globalCpuTrapHandler + load_pointer t1, (t1) + jalr t1 + + load_general_purpose_registers + # TODO: Load supervisor registers + + csrw sepc, t0 + + # TODO: When we will have a dedicated kernel stack per HART, + # We need to make sure to revert SP before swapping it back + csrr sp, sscratch + + sret diff --git a/src/Kernel/Platforms/RiscV/SupervisorTrapEntry.S b/src/Kernel/Platforms/RiscV/SupervisorTrapEntry.S deleted file mode 100644 index 08548c3..0000000 --- a/src/Kernel/Platforms/RiscV/SupervisorTrapEntry.S +++ /dev/null @@ -1,8 +0,0 @@ -#include "AsmCommon.h" - -.global supervisor_trap_entry - -.section .text.interrupt - -supervisor_trap_entry: - sret diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index c54931b..1c56049 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -36,4 +36,22 @@ Test(Cpu, CpuReadCycle) TestAssertGreaterThan(cycle2, cycle1); } -// TODO: Next Supervisor trap entry +void TestTrapHandler(CpuTrapFrame* trapFrame) +{ + auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); + KernelConsolePrint(String("Test Trap %x\n"), programCounter); + TestAssertEquals(0, programCounter); + + CpuClearPendingInterrupts(CpuInterruptType_Timer); + CpuDisableInterrupts(CpuInterruptType_All); +} + +Test(Cpu, CpuTrapHandler) +{ + // Arrange + CpuSetTrapHandler(TestTrapHandler); + CpuEnableInterrupts(CpuInterruptType_Timer); + BiosSetTimer(CpuReadTime()); + KernelConsolePrint(String("Test finieshed \n")); + CpuSetTrapHandler(nullptr); +} From 9b5760ddc13e6f75801f36181bd24f7f45639053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Tue, 10 Jun 2025 22:28:10 +0200 Subject: [PATCH 04/11] Fix a bug in riscv32 trap stack --- src/Kernel/Platforms/RiscV/AsmCommon.h | 3 +- src/Kernel/Platforms/RiscV/Cpu.c | 52 ++++++++++++++++++-- src/Kernel/Platforms/RiscV/KernelTrapEntry.S | 9 ++-- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/Kernel/Platforms/RiscV/AsmCommon.h b/src/Kernel/Platforms/RiscV/AsmCommon.h index c4d782d..77d9a1b 100644 --- a/src/Kernel/Platforms/RiscV/AsmCommon.h +++ b/src/Kernel/Platforms/RiscV/AsmCommon.h @@ -20,7 +20,8 @@ .macro save_general_purpose_registers - addi sp, sp, -(31 * PTR_SIZE) + addi sp, sp, -32 * PTR_SIZE + save_pointer x1, 0 * PTR_SIZE(sp) save_pointer x2, 1 * PTR_SIZE(sp) save_pointer x3, 2 * PTR_SIZE(sp) diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index 75e8776..895a73d 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -3,10 +3,40 @@ struct CpuTrapFrame { - uintptr_t PC; + uintptr_t RA; + uintptr_t SP; + uintptr_t GP; + uintptr_t TP; + uintptr_t T0; + uintptr_t T1; + uintptr_t T2; + uintptr_t S0; + uintptr_t S1; + uintptr_t A0; + uintptr_t A1; + uintptr_t A2; + uintptr_t A3; + uintptr_t A4; + uintptr_t A5; + uintptr_t A6; + uintptr_t A7; + uintptr_t S2; + uintptr_t S3; + uintptr_t S4; + uintptr_t S5; + uintptr_t S6; + uintptr_t S7; + uintptr_t S8; + uintptr_t S9; + uintptr_t S10; + uintptr_t S11; + uintptr_t T3; + uintptr_t T4; + uintptr_t T5; + uintptr_t T6; }; -extern void supervisor_trap_entry(); +extern void kernel_trap_entry(); CpuTrapHandler globalCpuTrapHandler; @@ -88,7 +118,7 @@ inline void CpuSetTrapHandler(CpuTrapHandler trapHandler) "csrw stvec, %0\n" "csrsi sstatus, 2" : - : "r" (supervisor_trap_entry)); + : "r" (kernel_trap_entry)); } else { @@ -139,5 +169,19 @@ inline void CpuWaitForInterrupt() inline uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame) { - return trapFrame->PC; + // TODO: Move that to ConsoleLogTrapFrame + KernelConsolePrint(String("raw ptr = %x\n"), trapFrame); + + KernelConsolePrint(String("RA: %x\n"), trapFrame->RA); + KernelConsolePrint(String("SP: %x\n"), trapFrame->SP); + KernelConsolePrint(String("GP: %x\n"), trapFrame->GP); + KernelConsolePrint(String("TP: %x\n"), trapFrame->TP); + KernelConsolePrint(String("T0: %x\n"), trapFrame->T0); + KernelConsolePrint(String("T1: %x\n"), trapFrame->T1); + KernelConsolePrint(String("T2: %x\n"), trapFrame->T2); + KernelConsolePrint(String("S0: %x\n"), trapFrame->S0); + KernelConsolePrint(String("S1: %x\n"), trapFrame->S1); + KernelConsolePrint(String("A0: %x\n"), trapFrame->A0); + + return trapFrame->T0; } diff --git a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S index d03dde5..89fe090 100644 --- a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S +++ b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S @@ -1,23 +1,26 @@ #include "AsmCommon.h" -.global supervisor_trap_entry # TODO: Rename +.global kernel_trap_entry # TODO: Rename .section .text.interrupt -supervisor_trap_entry: +kernel_trap_entry: # TODO: We will need to do a switch later when we manage MMU # to give the trap handler a kernel space stack independant of user mode. # For now, we just save the current SP that is shared between kernel and user. csrw sscratch, sp csrr t0, sepc + li a0, 5 + save_general_purpose_registers # TODO: Save supervisor registers - mv a0, sp # TODO: I don't know why we should have this one la t1, globalCpuTrapHandler load_pointer t1, (t1) + + mv a0, sp jalr t1 load_general_purpose_registers From 592aa9b68d739ced317fae080ce8af8831ec7df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Wed, 11 Jun 2025 14:18:56 +0200 Subject: [PATCH 05/11] Implement proper KernelTrapEntry assembly code --- cmake/Toolchains/clang.cmake | 13 ++ src/Common/String.c | 35 ++++- src/Common/Test.h | 13 +- src/Kernel/KernelMain.c | 14 +- src/Kernel/Platform.h | 7 + src/Kernel/Platforms/RiscV/AsmCommon.h | 154 +++++++++++-------- src/Kernel/Platforms/RiscV/CMakeLists.txt | 2 +- src/Kernel/Platforms/RiscV/Cpu.c | 75 +++++++-- src/Kernel/Platforms/RiscV/KernelTrapEntry.S | 21 ++- tests/Kernel/CpuTests.c | 11 +- 10 files changed, 238 insertions(+), 107 deletions(-) diff --git a/cmake/Toolchains/clang.cmake b/cmake/Toolchains/clang.cmake index 6f62560..d96e18e 100644 --- a/cmake/Toolchains/clang.cmake +++ b/cmake/Toolchains/clang.cmake @@ -21,6 +21,19 @@ if(NOT CMAKE_C_COMPILER OR NOT CMAKE_ASM_COMPILER) message(FATAL_ERROR "Could not find Clang.") endif() + get_filename_component(_LLVM_BIN_DIR "${_CLANG}" DIRECTORY) + + find_program(CMAKE_OBJCOPY # standard CMake cache variable + NAMES llvm-objcopy objcopy + HINTS "${_LLVM_BIN_DIR}" + "${_BREW_LLVM_PREFIX}/bin" + "C:\\Program Files\\LLVM\\bin" + NO_CMAKE_SYSTEM_PATH) + + if(NOT CMAKE_OBJCOPY) + message(FATAL_ERROR "Could not find llvm-objcopy or objcopy in ${_LLVM_BIN_DIR}") + endif() + set(CMAKE_C_COMPILER "${_CLANG}" CACHE FILEPATH "C compiler" FORCE) set(CMAKE_ASM_COMPILER "${_CLANG}" CACHE FILEPATH "ASM compiler" FORCE) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/src/Common/String.c b/src/Common/String.c index 830a9cb..1f09819 100644 --- a/src/Common/String.c +++ b/src/Common/String.c @@ -31,6 +31,7 @@ void StringFormat(SpanChar* destination, ReadOnlySpanChar message, ...) va_end(vargs); } +// TODO: Refactor this function void StringFormatVargs(SpanChar* destination, ReadOnlySpanChar message, va_list vargs) { uint32_t length = 0; @@ -97,13 +98,43 @@ void StringFormatVargs(SpanChar* destination, ReadOnlySpanChar message, va_list break; } + case 'l': + { + int64_t decimalArgument = va_arg(vargs, int64_t); + + // HACK: We should do a code that compile 32 and 64-bit + int32_t magnitude = (int32_t)decimalArgument; + + if (decimalArgument < 0) + { + destination->Pointer[length++] = '-'; + magnitude = -magnitude; + } + + int32_t divisor = 1; + + while ((magnitude / divisor) > 9) + { + divisor *= 10; + } + + while (divisor > 0) + { + destination->Pointer[length++] = '0' + magnitude / divisor; + + magnitude %= divisor; + divisor /= 10; + } + break; + } + case 'x': { - uint64_t hexaArgument = va_arg(vargs, uint64_t); + uintptr_t hexaArgument = va_arg(vargs, uintptr_t); destination->Pointer[length++] = '0'; destination->Pointer[length++] = 'x'; - for (int64_t i = (sizeof(uintptr_t) * 2) - 1; i >= 0; i--) + for (int32_t i = (sizeof(uintptr_t) * 2) - 1; i >= 0; i--) { unsigned nibble = (hexaArgument >> (i * 4)) & 0xf; destination->Pointer[length++] = "0123456789abcdef"[nibble]; diff --git a/src/Common/Test.h b/src/Common/Test.h index 8436d67..5621d58 100644 --- a/src/Common/Test.h +++ b/src/Common/Test.h @@ -50,17 +50,20 @@ extern SpanChar globalTestLastErrorMessage; do { \ if (!(expr)) { \ TestEntry* testEntry = &globalTests[globalCurrentTestIndex]; \ - testEntry->HasError = true; \ - StringFormat(&globalTestLastErrorMessage, String("%s\n Expected: %s\n Actual: %d %s %d"), __FILE__, #expr, expected, operator, actual); \ - return; \ + if (!testEntry->HasError) \ + { \ + testEntry->HasError = true; \ + StringFormat(&globalTestLastErrorMessage, String("%s\n Expected: %s\n Actual: %d %s %d"), __FILE__, #expr, expected, operator, actual); \ + } \ } \ } while (false) -// BUG: There is a bug in the assert only in 32-bit version, when the assert fail +// BUG: There is a bug in the assert only in 32-bit version, when the assert fail maybe due to 64 bit values used in the comparison like with the time #define TestAssertEquals(expected, actual) TestAssertCore((expected) == (actual), expected, actual, "==") #define TestAssertNotEquals(expected, actual) TestAssertCore((expected) != (actual), expected, actual, "!=") #define TestAssertGreaterThan(expected, actual) TestAssertCore((expected) > (actual), expected, actual, ">") +// TODO: Adapt the macro like the core one #define TestAssertStringEquals(expected, actual) \ do { \ if (finalString.Length != destination.Length) \ @@ -68,7 +71,6 @@ extern SpanChar globalTestLastErrorMessage; TestEntry* testEntry = &globalTests[globalCurrentTestIndex]; \ testEntry->HasError = true; \ StringFormat(&globalTestLastErrorMessage, String("%s\n Expected: (%s.Length) == (%s.Length)\n Actual: %d == %d"), __FILE__, #expected, #actual, expected.Length, actual.Length); \ - return; \ } \ \ if (!StringEquals(expected, actual)) \ @@ -76,7 +78,6 @@ extern SpanChar globalTestLastErrorMessage; TestEntry* testEntry = &globalTests[globalCurrentTestIndex]; \ testEntry->HasError = true; \ StringFormat(&globalTestLastErrorMessage, String("%s\n Expected: (%s) == (%s)\n Actual: \"%s\" == \"%s\""), __FILE__, #expected, #actual, expected.Pointer, actual.Pointer); \ - return; \ } \ } while (false) diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 6e89a54..68fa79f 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -14,11 +14,21 @@ const char KernelLogo[] = void KernelTrapHandler(CpuTrapFrame* trapFrame) { + auto trapCause = CpuTrapFrameGetTrapCause(trapFrame); + + switch (trapCause) + { + default: + KernelFailure(String("Unknown Kernel Trap Cause."), 1); + } + + CpuLogTrapFrame(trapFrame); auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); - CpuClearPendingInterrupts(CpuInterruptType_Timer); - KernelConsolePrint(String("Kernel trap handler: %d (PC=%x).\n"), CpuReadTime(), programCounter); + KernelConsolePrint(String("Kernel trap handler: %l (PC=%x).\n"), CpuReadTime(), programCounter); + KernelConsolePrint(String("Test=%x.\n"), programCounter); + CpuClearPendingInterrupts(CpuInterruptType_Timer); //CpuDisableInterrupts(CpuInterruptType_Timer); //SbiSetTimer((uint64_t)-1); BiosSetTimer(CpuReadTime() + 10000000); diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index 234a26d..503335f 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -20,6 +20,11 @@ typedef enum CpuInterruptType_All = 0xFF, } CpuInterruptType; +typedef enum +{ + CpuTrapCause_Unknown +} CpuTrapCause; + struct CpuTrapFrame; typedef struct CpuTrapFrame CpuTrapFrame; @@ -33,6 +38,8 @@ void CpuDisableInterrupts(CpuInterruptType types); void CpuClearPendingInterrupts(CpuInterruptType types); void CpuWaitForInterrupt(); +void CpuLogTrapFrame(const CpuTrapFrame* trapFrame); +CpuTrapCause CpuTrapFrameGetTrapCause(const CpuTrapFrame* trapFrame); uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame); diff --git a/src/Kernel/Platforms/RiscV/AsmCommon.h b/src/Kernel/Platforms/RiscV/AsmCommon.h index 77d9a1b..2efa908 100644 --- a/src/Kernel/Platforms/RiscV/AsmCommon.h +++ b/src/Kernel/Platforms/RiscV/AsmCommon.h @@ -19,74 +19,96 @@ #endif -.macro save_general_purpose_registers - addi sp, sp, -32 * PTR_SIZE +.macro save_general_purpose_registers addr + save_pointer x1, 0 * PTR_SIZE(\addr) + save_pointer x2, 1 * PTR_SIZE(\addr) + save_pointer x3, 2 * PTR_SIZE(\addr) + save_pointer x4, 3 * PTR_SIZE(\addr) + save_pointer x5, 4 * PTR_SIZE(\addr) + save_pointer x6, 5 * PTR_SIZE(\addr) + save_pointer x7, 6 * PTR_SIZE(\addr) + save_pointer x8, 7 * PTR_SIZE(\addr) + save_pointer x9, 8 * PTR_SIZE(\addr) + save_pointer x10, 9 * PTR_SIZE(\addr) + save_pointer x11, 10 * PTR_SIZE(\addr) + save_pointer x12, 11 * PTR_SIZE(\addr) + save_pointer x13, 12 * PTR_SIZE(\addr) + save_pointer x14, 13 * PTR_SIZE(\addr) + save_pointer x15, 14 * PTR_SIZE(\addr) + save_pointer x16, 15 * PTR_SIZE(\addr) + save_pointer x17, 16 * PTR_SIZE(\addr) + save_pointer x18, 17 * PTR_SIZE(\addr) + save_pointer x19, 18 * PTR_SIZE(\addr) + save_pointer x20, 19 * PTR_SIZE(\addr) + save_pointer x21, 20 * PTR_SIZE(\addr) + save_pointer x22, 21 * PTR_SIZE(\addr) + save_pointer x23, 22 * PTR_SIZE(\addr) + save_pointer x24, 23 * PTR_SIZE(\addr) + save_pointer x25, 24 * PTR_SIZE(\addr) + save_pointer x26, 25 * PTR_SIZE(\addr) + save_pointer x27, 26 * PTR_SIZE(\addr) + save_pointer x28, 27 * PTR_SIZE(\addr) + save_pointer x29, 28 * PTR_SIZE(\addr) + save_pointer x30, 29 * PTR_SIZE(\addr) + save_pointer x31, 30 * PTR_SIZE(\addr) +.endm - save_pointer x1, 0 * PTR_SIZE(sp) - save_pointer x2, 1 * PTR_SIZE(sp) - save_pointer x3, 2 * PTR_SIZE(sp) - save_pointer x4, 3 * PTR_SIZE(sp) - save_pointer x5, 4 * PTR_SIZE(sp) - save_pointer x6, 5 * PTR_SIZE(sp) - save_pointer x7, 6 * PTR_SIZE(sp) - save_pointer x8, 7 * PTR_SIZE(sp) - save_pointer x9, 8 * PTR_SIZE(sp) - save_pointer x10, 9 * PTR_SIZE(sp) - save_pointer x11, 10 * PTR_SIZE(sp) - save_pointer x12, 11 * PTR_SIZE(sp) - save_pointer x13, 12 * PTR_SIZE(sp) - save_pointer x14, 13 * PTR_SIZE(sp) - save_pointer x15, 14 * PTR_SIZE(sp) - save_pointer x16, 15 * PTR_SIZE(sp) - save_pointer x17, 16 * PTR_SIZE(sp) - save_pointer x18, 17 * PTR_SIZE(sp) - save_pointer x19, 18 * PTR_SIZE(sp) - save_pointer x20, 19 * PTR_SIZE(sp) - save_pointer x21, 20 * PTR_SIZE(sp) - save_pointer x22, 21 * PTR_SIZE(sp) - save_pointer x23, 22 * PTR_SIZE(sp) - save_pointer x24, 23 * PTR_SIZE(sp) - save_pointer x25, 24 * PTR_SIZE(sp) - save_pointer x26, 25 * PTR_SIZE(sp) - save_pointer x27, 26 * PTR_SIZE(sp) - save_pointer x28, 27 * PTR_SIZE(sp) - save_pointer x29, 28 * PTR_SIZE(sp) - save_pointer x30, 29 * PTR_SIZE(sp) - save_pointer x31, 30 * PTR_SIZE(sp) +.macro load_general_purpose_registers addr + load_pointer x1, 0 * PTR_SIZE(\addr) + load_pointer x2, 1 * PTR_SIZE(\addr) + load_pointer x3, 2 * PTR_SIZE(\addr) + load_pointer x4, 3 * PTR_SIZE(\addr) + load_pointer x5, 4 * PTR_SIZE(\addr) + load_pointer x6, 5 * PTR_SIZE(\addr) + load_pointer x7, 6 * PTR_SIZE(\addr) + load_pointer x8, 7 * PTR_SIZE(\addr) + load_pointer x9, 8 * PTR_SIZE(\addr) + load_pointer x10, 9 * PTR_SIZE(\addr) + load_pointer x11, 10 * PTR_SIZE(\addr) + load_pointer x12, 11 * PTR_SIZE(\addr) + load_pointer x13, 12 * PTR_SIZE(\addr) + load_pointer x14, 13 * PTR_SIZE(\addr) + load_pointer x15, 14 * PTR_SIZE(\addr) + load_pointer x16, 15 * PTR_SIZE(\addr) + load_pointer x17, 16 * PTR_SIZE(\addr) + load_pointer x18, 17 * PTR_SIZE(\addr) + load_pointer x19, 18 * PTR_SIZE(\addr) + load_pointer x20, 19 * PTR_SIZE(\addr) + load_pointer x21, 20 * PTR_SIZE(\addr) + load_pointer x22, 21 * PTR_SIZE(\addr) + load_pointer x23, 22 * PTR_SIZE(\addr) + load_pointer x24, 23 * PTR_SIZE(\addr) + load_pointer x25, 24 * PTR_SIZE(\addr) + load_pointer x26, 25 * PTR_SIZE(\addr) + load_pointer x27, 26 * PTR_SIZE(\addr) + load_pointer x28, 27 * PTR_SIZE(\addr) + load_pointer x29, 28 * PTR_SIZE(\addr) + load_pointer x30, 29 * PTR_SIZE(\addr) + load_pointer x31, 30 * PTR_SIZE(\addr) .endm -.macro load_general_purpose_registers - load_pointer x1, 0 * PTR_SIZE(sp) - load_pointer x2, 1 * PTR_SIZE(sp) - load_pointer x3, 2 * PTR_SIZE(sp) - load_pointer x4, 3 * PTR_SIZE(sp) - load_pointer x5, 4 * PTR_SIZE(sp) - load_pointer x6, 5 * PTR_SIZE(sp) - load_pointer x7, 6 * PTR_SIZE(sp) - load_pointer x8, 7 * PTR_SIZE(sp) - load_pointer x9, 8 * PTR_SIZE(sp) - load_pointer x10, 9 * PTR_SIZE(sp) - load_pointer x11, 10 * PTR_SIZE(sp) - load_pointer x12, 11 * PTR_SIZE(sp) - load_pointer x13, 12 * PTR_SIZE(sp) - load_pointer x14, 13 * PTR_SIZE(sp) - load_pointer x15, 14 * PTR_SIZE(sp) - load_pointer x16, 15 * PTR_SIZE(sp) - load_pointer x17, 16 * PTR_SIZE(sp) - load_pointer x18, 17 * PTR_SIZE(sp) - load_pointer x19, 18 * PTR_SIZE(sp) - load_pointer x20, 19 * PTR_SIZE(sp) - load_pointer x21, 20 * PTR_SIZE(sp) - load_pointer x22, 21 * PTR_SIZE(sp) - load_pointer x23, 22 * PTR_SIZE(sp) - load_pointer x24, 23 * PTR_SIZE(sp) - load_pointer x25, 24 * PTR_SIZE(sp) - load_pointer x26, 25 * PTR_SIZE(sp) - load_pointer x27, 26 * PTR_SIZE(sp) - load_pointer x28, 27 * PTR_SIZE(sp) - load_pointer x29, 28 * PTR_SIZE(sp) - load_pointer x30, 29 * PTR_SIZE(sp) - load_pointer x31, 30 * PTR_SIZE(sp) +.macro save_supervisor_registers addr + csrr t1, sepc + save_pointer t1, 0 * PTR_SIZE(\addr) + csrr t1, sstatus + save_pointer t1, 1 * PTR_SIZE(\addr) + csrr t1, sscratch + save_pointer t1, 2 * PTR_SIZE(\addr) + csrr t1, scause + save_pointer t1, 3 * PTR_SIZE(\addr) + csrr t1, stval + save_pointer t1, 4 * PTR_SIZE(\addr) +.endm - addi sp, sp, (31 * PTR_SIZE) +.macro load_supervisor_registers addr + load_pointer t1, 0 * PTR_SIZE(\addr) + csrw sepc, t1 + load_pointer t1, 1 * PTR_SIZE(\addr) + csrw sstatus, t1 + load_pointer t1, 2 * PTR_SIZE(\addr) + csrw sscratch, t1 + load_pointer t1, 3 * PTR_SIZE(\addr) + csrw scause, t1 + load_pointer t1, 4 * PTR_SIZE(\addr) + csrw stval, t1 .endm diff --git a/src/Kernel/Platforms/RiscV/CMakeLists.txt b/src/Kernel/Platforms/RiscV/CMakeLists.txt index 14df7dc..3f3da4f 100644 --- a/src/Kernel/Platforms/RiscV/CMakeLists.txt +++ b/src/Kernel/Platforms/RiscV/CMakeLists.txt @@ -12,7 +12,7 @@ set_target_properties(Kernel PROPERTIES ) add_custom_command(TARGET Kernel POST_BUILD - COMMAND llvm-objcopy + COMMAND "${CMAKE_OBJCOPY}" --output-target=binary # -O binary --binary-architecture=riscv:${_MARCH} $ # kernel.elf (source) diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index 895a73d..87325fb 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -1,7 +1,8 @@ #include "Types.h" +#include "../../KernelConsole.h" #include "../../Platform.h" -struct CpuTrapFrame +typedef struct { uintptr_t RA; uintptr_t SP; @@ -34,8 +35,26 @@ struct CpuTrapFrame uintptr_t T4; uintptr_t T5; uintptr_t T6; +} GeneralPurposeRegisters; + +typedef struct +{ + uintptr_t Epc; + uintptr_t Status; + uintptr_t Scratch; + uintptr_t Cause; + uintptr_t TrapValue; +} SupervisorRegisters; + +struct CpuTrapFrame +{ + // TODO: Add a TrapFrameType to specify if it is partial, full, float, vector, etc. + GeneralPurposeRegisters GeneralPurposeRegisters; + SupervisorRegisters SupervisorRegisters; }; +static_assert(sizeof(CpuTrapFrame) % 16 == 0); + extern void kernel_trap_entry(); CpuTrapHandler globalCpuTrapHandler; @@ -167,21 +186,45 @@ inline void CpuWaitForInterrupt() __asm__ __volatile__("wfi"); } +void LogGeneralPurposeRegisters(const GeneralPurposeRegisters* generalPurposeRegisters) +{ + KernelConsolePrint(String("ra: %x sp: %x gp: %x\n"), generalPurposeRegisters->RA, generalPurposeRegisters->SP, generalPurposeRegisters->GP); + KernelConsolePrint(String("tp: %x t0: %x t1: %x\n"), generalPurposeRegisters->TP, generalPurposeRegisters->T0, generalPurposeRegisters->T1); + KernelConsolePrint(String("t2: %x s0: %x s1: %x\n"), generalPurposeRegisters->T2, generalPurposeRegisters->S0, generalPurposeRegisters->S1); + KernelConsolePrint(String("a0: %x a1: %x a2: %x\n"), generalPurposeRegisters->A0, generalPurposeRegisters->A1, generalPurposeRegisters->A2); + KernelConsolePrint(String("a3: %x a4: %x a5: %x\n"), generalPurposeRegisters->A3, generalPurposeRegisters->A4, generalPurposeRegisters->A5); + KernelConsolePrint(String("a6: %x a7: %x s2: %x\n"), generalPurposeRegisters->A6, generalPurposeRegisters->A7, generalPurposeRegisters->S2); + KernelConsolePrint(String("s3: %x s4: %x s5: %x\n"), generalPurposeRegisters->S3, generalPurposeRegisters->S4, generalPurposeRegisters->S5); + KernelConsolePrint(String("s6: %x s7: %x s8: %x\n"), generalPurposeRegisters->S6, generalPurposeRegisters->S7, generalPurposeRegisters->S8); + KernelConsolePrint(String("s9: %x s10: %x s11: %x\n"), generalPurposeRegisters->S9, generalPurposeRegisters->S10, generalPurposeRegisters->S11); + KernelConsolePrint(String("t3: %x t4: %x t5: %x\n"), generalPurposeRegisters->T3, generalPurposeRegisters->T4, generalPurposeRegisters->T5); + KernelConsolePrint(String("t6: %x\n"), generalPurposeRegisters->T6); +} + +void LogSupervisorRegisters(const SupervisorRegisters* supervisorRegisters) +{ + KernelConsolePrint(String("sepc: %x sstatus: %x sscratch: %x\n"), supervisorRegisters->Epc, supervisorRegisters->Status, supervisorRegisters->Scratch); + KernelConsolePrint(String("scause: %x stval: %x\n"), supervisorRegisters->Cause, supervisorRegisters->TrapValue); +} + +void CpuLogTrapFrame(const CpuTrapFrame* trapFrame) +{ + KernelConsolePrint(String("Trap Frame:\n")); + KernelConsolePrint(String("===========\n\n")); + + KernelConsolePrint(String("General Purpose Registers:\n")); + LogGeneralPurposeRegisters(&trapFrame->GeneralPurposeRegisters); + + KernelConsolePrint(String("\nSupervisor Registers:\n")); + LogSupervisorRegisters(&trapFrame->SupervisorRegisters); +} + +CpuTrapCause CpuTrapFrameGetTrapCause(const CpuTrapFrame* trapFrame) +{ + return CpuTrapCause_Unknown; +} + inline uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame) { - // TODO: Move that to ConsoleLogTrapFrame - KernelConsolePrint(String("raw ptr = %x\n"), trapFrame); - - KernelConsolePrint(String("RA: %x\n"), trapFrame->RA); - KernelConsolePrint(String("SP: %x\n"), trapFrame->SP); - KernelConsolePrint(String("GP: %x\n"), trapFrame->GP); - KernelConsolePrint(String("TP: %x\n"), trapFrame->TP); - KernelConsolePrint(String("T0: %x\n"), trapFrame->T0); - KernelConsolePrint(String("T1: %x\n"), trapFrame->T1); - KernelConsolePrint(String("T2: %x\n"), trapFrame->T2); - KernelConsolePrint(String("S0: %x\n"), trapFrame->S0); - KernelConsolePrint(String("S1: %x\n"), trapFrame->S1); - KernelConsolePrint(String("A0: %x\n"), trapFrame->A0); - - return trapFrame->T0; + return trapFrame->GeneralPurposeRegisters.T0; } diff --git a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S index 89fe090..b718b9f 100644 --- a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S +++ b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S @@ -9,13 +9,15 @@ kernel_trap_entry: # to give the trap handler a kernel space stack independant of user mode. # For now, we just save the current SP that is shared between kernel and user. csrw sscratch, sp - csrr t0, sepc - li a0, 5 - - save_general_purpose_registers - # TODO: Save supervisor registers + # TODO: For now we are saving all the Gprs but it should be revised later + # to optimize + addi sp, sp, -(36 * PTR_SIZE) + save_general_purpose_registers sp + mv t0, sp + addi t0, t0, 31 * PTR_SIZE + save_supervisor_registers t0 la t1, globalCpuTrapHandler load_pointer t1, (t1) @@ -23,10 +25,13 @@ kernel_trap_entry: mv a0, sp jalr t1 - load_general_purpose_registers - # TODO: Load supervisor registers + load_general_purpose_registers sp + + mv t0, sp + addi t0, t0, 31 * PTR_SIZE + load_supervisor_registers t0 - csrw sepc, t0 + addi sp, sp, (36 * PTR_SIZE) # TODO: When we will have a dedicated kernel stack per HART, # We need to make sure to revert SP before swapping it back diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index 1c56049..45b232f 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -38,20 +38,19 @@ Test(Cpu, CpuReadCycle) void TestTrapHandler(CpuTrapFrame* trapFrame) { - auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); - KernelConsolePrint(String("Test Trap %x\n"), programCounter); - TestAssertEquals(0, programCounter); - CpuClearPendingInterrupts(CpuInterruptType_Timer); CpuDisableInterrupts(CpuInterruptType_All); + + // Assert + auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); + TestAssertNotEquals(0, programCounter); } Test(Cpu, CpuTrapHandler) { - // Arrange + // Arrange / Act CpuSetTrapHandler(TestTrapHandler); CpuEnableInterrupts(CpuInterruptType_Timer); BiosSetTimer(CpuReadTime()); - KernelConsolePrint(String("Test finieshed \n")); CpuSetTrapHandler(nullptr); } From 42cfcc55be25d8f7a5bf89cccd44ddfcc740bc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Wed, 11 Jun 2025 15:40:16 +0200 Subject: [PATCH 06/11] Update parsing RISC-V scause --- src/Kernel/KernelMain.c | 7 +++++-- src/Kernel/Platform.h | 5 ++++- src/Kernel/Platforms/RiscV/Cpu.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 68fa79f..491f5ed 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -14,15 +14,18 @@ const char KernelLogo[] = void KernelTrapHandler(CpuTrapFrame* trapFrame) { + CpuLogTrapFrame(trapFrame); auto trapCause = CpuTrapFrameGetTrapCause(trapFrame); switch (trapCause) { + case CpuTrapCause_InterruptTimer: + break; + default: - KernelFailure(String("Unknown Kernel Trap Cause."), 1); + KernelFailure(String("Unknown Kernel Trap Cause. (Cause=%x)"), trapCause); } - CpuLogTrapFrame(trapFrame); auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); KernelConsolePrint(String("Kernel trap handler: %l (PC=%x).\n"), CpuReadTime(), programCounter); diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index 503335f..07294a7 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -22,7 +22,10 @@ typedef enum typedef enum { - CpuTrapCause_Unknown + CpuTrapCause_Unknown, + CpuTrapCause_InterruptSoftware, + CpuTrapCause_InterruptTimer, + CpuTrapCause_InterruptExternal, } CpuTrapCause; struct CpuTrapFrame; diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index 87325fb..c879cd2 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -221,6 +221,35 @@ void CpuLogTrapFrame(const CpuTrapFrame* trapFrame) CpuTrapCause CpuTrapFrameGetTrapCause(const CpuTrapFrame* trapFrame) { + auto isInterrupt = (trapFrame->SupervisorRegisters.Cause >> (sizeof(uintptr_t) * 8 - 1) > 0); + auto causeCode = trapFrame->SupervisorRegisters.Cause & ((1ULL<<((sizeof(uintptr_t)*8)-1))-1); + + if (isInterrupt) + { + // TODO: Extract constants + switch (causeCode) + { + case 1: + return CpuTrapCause_InterruptSoftware; + + case 5: + return CpuTrapCause_InterruptTimer; + + case 9: + return CpuTrapCause_InterruptExternal; + } + } + + /* + switch (code) { + case 8: return TC_SYSCALL; + case 12: return TC_PAGE_FAULT_INS; + case 13: return TC_PAGE_FAULT_LOAD; + case 15: return TC_PAGE_FAULT_STORE; + case 2: return TC_ILLEGAL_INSTRUCTION; + default: return TC_OTHER; + }*/ + return CpuTrapCause_Unknown; } From e74d92b2d7e1cd8a97130707ef526ad2396cc856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 12 Jun 2025 22:13:20 +0200 Subject: [PATCH 07/11] WIP error handling --- src/Kernel/Kernel.c | 6 +- src/Kernel/KernelMain.c | 36 ++++++----- src/Kernel/Platform.h | 21 +++++-- src/Kernel/Platforms/RiscV/AsmCommon.h | 4 -- src/Kernel/Platforms/RiscV/Cpu.c | 86 ++++++++++++++++++++++---- tests/Kernel/CpuTests.c | 54 +++++++++++++--- 6 files changed, 158 insertions(+), 49 deletions(-) diff --git a/src/Kernel/Kernel.c b/src/Kernel/Kernel.c index 91a155c..01986f9 100644 --- a/src/Kernel/Kernel.c +++ b/src/Kernel/Kernel.c @@ -4,9 +4,9 @@ void KernelFailureCore(ReadOnlySpanChar file, uint32_t line, ReadOnlySpanChar message, ...) { - KernelConsolePrint(String("\x1b[31m\n ----------------\n")); - KernelConsolePrint(String("| KERNEL Failure |\n")); - KernelConsolePrint(String(" ----------------\n\n")); + KernelConsolePrint(String("\x1b[31m\n\xDA\xC4\xC4\xC4----------------\xBF\n")); + KernelConsolePrint(String("\xB3 KERNEL Failure |\n")); + KernelConsolePrint(String("\xC0----------------\xD9\n\n")); KernelConsolePrint(String("%s:%d\n"), file, line); va_list vargs; diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 491f5ed..2096a75 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -15,26 +15,29 @@ const char KernelLogo[] = void KernelTrapHandler(CpuTrapFrame* trapFrame) { CpuLogTrapFrame(trapFrame); - auto trapCause = CpuTrapFrameGetTrapCause(trapFrame); + auto trapCause = CpuTrapFrameGetCause(trapFrame); - switch (trapCause) + if (trapCause.Type == CpuTrapCauseType_Interrupt) { - case CpuTrapCause_InterruptTimer: - break; - - default: - KernelFailure(String("Unknown Kernel Trap Cause. (Cause=%x)"), trapCause); + switch (trapCause.InterruptType) + { + case CpuInterruptType_Timer: + CpuClearPendingInterrupts(CpuInterruptType_Timer); + //CpuDisableInterrupts(CpuInterruptType_Timer); + //SbiSetTimer((uint64_t)-1); + BiosSetTimer(CpuReadTime() + 10000000); + + auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); + KernelConsolePrint(String("Kernel trap handler: %l (PC=%x).\n"), CpuReadTime(), programCounter); + + return; + + default: + KernelFailure(String("Unknown interrupt type. (InterruptType: %x)"), trapCause.InterruptType); + } } - auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); - - KernelConsolePrint(String("Kernel trap handler: %l (PC=%x).\n"), CpuReadTime(), programCounter); - KernelConsolePrint(String("Test=%x.\n"), programCounter); - - CpuClearPendingInterrupts(CpuInterruptType_Timer); - //CpuDisableInterrupts(CpuInterruptType_Timer); - //SbiSetTimer((uint64_t)-1); - BiosSetTimer(CpuReadTime() + 10000000); + KernelFailure(String("Unknown Kernel Trap Cause. (Cause=%x)"), trapCause.Type); } void KernelMain() @@ -51,6 +54,7 @@ void KernelMain() while (true) { + CpuGenerateInvalidInstruction(); CpuWaitForInterrupt(); } } diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index 07294a7..b19f8d9 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -20,12 +20,16 @@ typedef enum CpuInterruptType_All = 0xFF, } CpuInterruptType; -typedef enum +typedef enum +{ + CpuTrapCauseType_Unknown, + CpuTrapCauseType_Interrupt, +} CpuTrapCauseType; + +typedef struct { - CpuTrapCause_Unknown, - CpuTrapCause_InterruptSoftware, - CpuTrapCause_InterruptTimer, - CpuTrapCause_InterruptExternal, + CpuTrapCauseType Type; + CpuInterruptType InterruptType; } CpuTrapCause; struct CpuTrapFrame; @@ -35,6 +39,10 @@ typedef void (*CpuTrapHandler)(struct CpuTrapFrame*); uint64_t CpuReadTime(); uint64_t CpuReadCycle(); + +void CpuGenerateInvalidInstruction(); +uintptr_t CpuComputeNextInstructionAddress(uintptr_t instructionAddress); + void CpuSetTrapHandler(CpuTrapHandler trapHandler); void CpuEnableInterrupts(CpuInterruptType types); void CpuDisableInterrupts(CpuInterruptType types); @@ -42,8 +50,9 @@ void CpuClearPendingInterrupts(CpuInterruptType types); void CpuWaitForInterrupt(); void CpuLogTrapFrame(const CpuTrapFrame* trapFrame); -CpuTrapCause CpuTrapFrameGetTrapCause(const CpuTrapFrame* trapFrame); +CpuTrapCause CpuTrapFrameGetCause(const CpuTrapFrame* trapFrame); uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame); +void CpuTrapFrameSetProgramCounter(CpuTrapFrame* trapFrame, uintptr_t value); typedef enum diff --git a/src/Kernel/Platforms/RiscV/AsmCommon.h b/src/Kernel/Platforms/RiscV/AsmCommon.h index 2efa908..5b17560 100644 --- a/src/Kernel/Platforms/RiscV/AsmCommon.h +++ b/src/Kernel/Platforms/RiscV/AsmCommon.h @@ -107,8 +107,4 @@ csrw sstatus, t1 load_pointer t1, 2 * PTR_SIZE(\addr) csrw sscratch, t1 - load_pointer t1, 3 * PTR_SIZE(\addr) - csrw scause, t1 - load_pointer t1, 4 * PTR_SIZE(\addr) - csrw stval, t1 .endm diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index c879cd2..78eeccf 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -2,6 +2,10 @@ #include "../../KernelConsole.h" #include "../../Platform.h" +#define RISCV_INTERRUPT_SOFTWARE 1 +#define RISCV_INTERRUPT_TIMER 5 +#define RISCV_INTERRUPT_EXTERNAL 9 + typedef struct { uintptr_t RA; @@ -65,17 +69,17 @@ uintptr_t ComputeCpuInterruptMask(CpuInterruptType types) if (types & CpuInterruptType_Software) { - mask |= (uintptr_t)1 << 1; + mask |= (uintptr_t)1 << RISCV_INTERRUPT_SOFTWARE; } if (types & CpuInterruptType_Timer) { - mask |= (uintptr_t)1 << 5; + mask |= (uintptr_t)1 << RISCV_INTERRUPT_TIMER; } if (types & CpuInterruptType_External) { - mask |= (uintptr_t)1 << 9; + mask |= (uintptr_t)1 << RISCV_INTERRUPT_EXTERNAL; } return mask; @@ -127,6 +131,48 @@ inline uint64_t CpuReadCycle() } #endif +inline void CpuGenerateInvalidInstruction() +{ + __asm__ volatile ("unimp"); +} + +/* Masks and “all-ones” patterns for the three fields we test. */ +#define RV_MASK_LOW2 0x0003u /* bits[1:0] */ +#define RV_MASK_MID3 0x001Cu /* bits[4:2] */ +#define RV_MASK_HIGH2 0x0060u /* bits[6:5] */ + +#define RV_PATTERN_LOW2_32 0x0003u /* 0b11 */ +#define RV_PATTERN_MID3_48 0x001Cu /* 0b111 << 2 */ +#define RV_PATTERN_HIGH2_64 0x0060u /* 0b11 << 5 */ + +/* Resulting instruction sizes in bytes. */ +#define RV_SIZE_16 2u +#define RV_SIZE_32 4u +#define RV_SIZE_48 6u +#define RV_SIZE_64 8u + +uintptr_t CpuComputeNextInstructionAddress(uintptr_t instructionAddress) +{ + /* Text might be in an execute-only segment; cast via unsigned char avoids UB. */ + const uint16_t firstHalfword = + *(const uint16_t *)(const unsigned char *)instructionAddress; + + /* --- 1. 16-bit? -------------------------------------------------------- */ + if ((firstHalfword & RV_MASK_LOW2) != RV_PATTERN_LOW2_32) + return instructionAddress + RV_SIZE_16; + + /* --- 2. 32-bit? -------------------------------------------------------- */ + if ((firstHalfword & RV_MASK_MID3) != RV_PATTERN_MID3_48) + return instructionAddress + RV_SIZE_32; + + /* --- 3. 48-bit? -------------------------------------------------------- */ + if ((firstHalfword & RV_MASK_HIGH2) != RV_PATTERN_HIGH2_64) + return instructionAddress + RV_SIZE_48; + + /* --- 4. Otherwise it must be 64-bit ----------------------------------- */ + return instructionAddress + RV_SIZE_64; +} + inline void CpuSetTrapHandler(CpuTrapHandler trapHandler) { globalCpuTrapHandler = trapHandler; @@ -219,27 +265,38 @@ void CpuLogTrapFrame(const CpuTrapFrame* trapFrame) LogSupervisorRegisters(&trapFrame->SupervisorRegisters); } -CpuTrapCause CpuTrapFrameGetTrapCause(const CpuTrapFrame* trapFrame) +CpuTrapCause CpuTrapFrameGetCause(const CpuTrapFrame* trapFrame) { auto isInterrupt = (trapFrame->SupervisorRegisters.Cause >> (sizeof(uintptr_t) * 8 - 1) > 0); auto causeCode = trapFrame->SupervisorRegisters.Cause & ((1ULL<<((sizeof(uintptr_t)*8)-1))-1); + auto interruptType = CpuInterruptType_None; + if (isInterrupt) { // TODO: Extract constants switch (causeCode) { - case 1: - return CpuTrapCause_InterruptSoftware; + case RISCV_INTERRUPT_SOFTWARE: + interruptType = CpuInterruptType_Software; + break; - case 5: - return CpuTrapCause_InterruptTimer; + case RISCV_INTERRUPT_TIMER: + interruptType = CpuInterruptType_Timer; + break; - case 9: - return CpuTrapCause_InterruptExternal; + case RISCV_INTERRUPT_EXTERNAL: + interruptType = CpuInterruptType_External; + break; } } + return (CpuTrapCause) + { + .Type = isInterrupt ? CpuTrapCauseType_Interrupt : CpuTrapCauseType_Unknown, + .InterruptType = interruptType + }; + /* switch (code) { case 8: return TC_SYSCALL; @@ -249,11 +306,14 @@ CpuTrapCause CpuTrapFrameGetTrapCause(const CpuTrapFrame* trapFrame) case 2: return TC_ILLEGAL_INSTRUCTION; default: return TC_OTHER; }*/ - - return CpuTrapCause_Unknown; } inline uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame) { - return trapFrame->GeneralPurposeRegisters.T0; + return trapFrame->SupervisorRegisters.Epc; +} + +void CpuTrapFrameSetProgramCounter(CpuTrapFrame* trapFrame, uintptr_t value) +{ + trapFrame->SupervisorRegisters.Epc = value; } diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index 45b232f..ae00b8c 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -36,21 +36,61 @@ Test(Cpu, CpuReadCycle) TestAssertGreaterThan(cycle2, cycle1); } -void TestTrapHandler(CpuTrapFrame* trapFrame) +bool hasTestTrapHandler_WithTimerInterruptRun = false; + +void TestTrapHandler_WithTimerInterrupt(CpuTrapFrame* trapFrame) { + hasTestTrapHandler_WithTimerInterruptRun = true; + CpuClearPendingInterrupts(CpuInterruptType_Timer); CpuDisableInterrupts(CpuInterruptType_All); + CpuSetTrapHandler(nullptr); - // Assert - auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); - TestAssertNotEquals(0, programCounter); + auto trapCause = CpuTrapFrameGetCause(trapFrame); + + TestAssertEquals(CpuTrapCauseType_Interrupt, trapCause.Type); + TestAssertEquals(CpuInterruptType_Timer, trapCause.InterruptType); } -Test(Cpu, CpuTrapHandler) +Test(Cpu, CpuTrapHandler_WithTimerInterrupt_HasCorrectCause) { - // Arrange / Act - CpuSetTrapHandler(TestTrapHandler); + // Arrange + CpuSetTrapHandler(TestTrapHandler_WithTimerInterrupt); CpuEnableInterrupts(CpuInterruptType_Timer); + + // Act BiosSetTimer(CpuReadTime()); + + // Assert + // TODO: AssertIsTrue + TestAssertEquals(true, hasTestTrapHandler_WithTimerInterruptRun); +} + +bool hasTestTrapHandler_WithInvalidInstructionRun = false; + +void TestTrapHandler_WithInvalidInstruction(CpuTrapFrame* trapFrame) +{ + hasTestTrapHandler_WithInvalidInstructionRun = true; CpuSetTrapHandler(nullptr); + + auto nextInstructionAddress = CpuComputeNextInstructionAddress(CpuTrapFrameGetProgramCounter(trapFrame)); + CpuTrapFrameSetProgramCounter(trapFrame, nextInstructionAddress); + + // Assert + auto trapCause = CpuTrapFrameGetCause(trapFrame); + + TestAssertEquals(CpuTrapCauseType_Interrupt, trapCause.Type); + TestAssertEquals(CpuInterruptType_Timer, trapCause.InterruptType); +} + +Test(Cpu, CpuTrapHandler_WithInvalidInstruction_HasCorrectCause) +{ + // Arrange + CpuSetTrapHandler(TestTrapHandler_WithInvalidInstruction); + + // Act + CpuGenerateInvalidInstruction(); + + // Assert + TestAssertEquals(true, hasTestTrapHandler_WithInvalidInstructionRun); } From ee0bdac6f81ebed72dcf538de9b2968d8a8215c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Sat, 14 Jun 2025 08:54:28 +0200 Subject: [PATCH 08/11] Refactor KernelConsole --- src/Common/Types.h | 8 +++ src/Kernel/Kernel.c | 9 +-- src/Kernel/KernelConsole.c | 75 +++++++++++++++++++++- src/Kernel/KernelConsole.h | 15 +++++ src/Kernel/KernelMain.c | 11 +++- src/Kernel/KernelTest.c | 23 ++++--- src/Kernel/Platform.h | 22 +++++++ src/Kernel/Platforms/RiscV/Cpu.c | 105 +++++++++++++++++++++++++------ tests/Kernel/CpuTests.c | 13 ++-- 9 files changed, 240 insertions(+), 41 deletions(-) diff --git a/src/Common/Types.h b/src/Common/Types.h index 75dd029..b939e47 100644 --- a/src/Common/Types.h +++ b/src/Common/Types.h @@ -27,3 +27,11 @@ static_assert(sizeof(uintptr_t) == sizeof(void *), "uintptr_t is not pointer-siz #define va_start __builtin_va_start #define va_end __builtin_va_end #define va_arg __builtin_va_arg + +typedef struct +{ + uint8_t Red; + uint8_t Green; + uint8_t Blue; + uint8_t Alpha; +} Color; diff --git a/src/Kernel/Kernel.c b/src/Kernel/Kernel.c index 01986f9..8a1ae46 100644 --- a/src/Kernel/Kernel.c +++ b/src/Kernel/Kernel.c @@ -1,12 +1,12 @@ #include "Kernel.h" #include "KernelConsole.h" +#include "Memory.h" #include "Platform.h" void KernelFailureCore(ReadOnlySpanChar file, uint32_t line, ReadOnlySpanChar message, ...) { - KernelConsolePrint(String("\x1b[31m\n\xDA\xC4\xC4\xC4----------------\xBF\n")); - KernelConsolePrint(String("\xB3 KERNEL Failure |\n")); - KernelConsolePrint(String("\xC0----------------\xD9\n\n")); + KernelConsoleSetForegroundColor(KernelConsoleColorError); + KernelConsolePrintBoxMessage(String("Kernel Failure")); KernelConsolePrint(String("%s:%d\n"), file, line); va_list vargs; @@ -15,7 +15,8 @@ void KernelFailureCore(ReadOnlySpanChar file, uint32_t line, ReadOnlySpanChar me auto tmp = StackAllocChar(256); StringFormatVargs(&tmp, message, vargs); - KernelConsolePrint(String("%s\n\n\x1b[0m"), tmp); + KernelConsolePrint(String("%s\n\n"), tmp); + KernelConsoleResetStyle(); va_end(vargs); diff --git a/src/Kernel/KernelConsole.c b/src/Kernel/KernelConsole.c index 5d0ff3e..27eefb0 100644 --- a/src/Kernel/KernelConsole.c +++ b/src/Kernel/KernelConsole.c @@ -1,8 +1,8 @@ #include "KernelConsole.h" +#include "Memory.h" #include "String.h" #include "Platform.h" -// TODO: See https://github.com/riscv-software-src/opensbi/blob/master/lib/sbi/sbi_console.c#L440 for more implementation details void KernelConsolePrint(ReadOnlySpanChar message, ...) { auto output = StackAllocChar(2048); @@ -16,3 +16,76 @@ void KernelConsolePrint(ReadOnlySpanChar message, ...) BiosDebugConsoleWrite(ToReadOnlySpanChar(output)); } + +void KernelConsoleSetForegroundColor(Color color) +{ + KernelConsolePrint(String("\x1b[38;2;%d;%d;%dm"), (int32_t)color.Red, (int32_t)color.Green, (int32_t)color.Blue); +} + +void KernelConsoleResetStyle() +{ + KernelConsolePrint(String("\x1b[0m")); + KernelConsoleSetForegroundColor(KernelConsoleColorNormal); +} + +void FormatBoxedMessage(SpanChar destination, ReadOnlySpanChar message) +{ + auto upLeftCorner = String("┌"); + auto upRightCorner = String("┐"); + auto downLeftCorner = String("└"); + auto downRightCorner = String("┘"); + auto horizontalLine = String("─"); + auto verticalLine = String("│"); + + MemoryCopy(destination, upLeftCorner); + destination = SpanSliceFrom(destination, upLeftCorner.Length); + + for (uint32_t i = 0; i < message.Length + 2; i++) + { + MemoryCopy(destination, horizontalLine); + destination = SpanSliceFrom(destination, horizontalLine.Length); + } + + MemoryCopy(destination, upRightCorner); + destination = SpanSliceFrom(destination, upRightCorner.Length); + + MemoryCopy(destination, String("\n")); + destination = SpanSliceFrom(destination, 1); + + MemoryCopy(destination, verticalLine); + destination = SpanSliceFrom(destination, verticalLine.Length); + + MemoryCopy(destination, String(" ")); + destination = SpanSliceFrom(destination, 1); + + MemoryCopy(destination, message); + destination = SpanSliceFrom(destination, message.Length); + + MemoryCopy(destination, String(" ")); + destination = SpanSliceFrom(destination, 1); + + MemoryCopy(destination, verticalLine); + destination = SpanSliceFrom(destination, verticalLine.Length); + + MemoryCopy(destination, String("\n")); + destination = SpanSliceFrom(destination, 1); + + MemoryCopy(destination, downLeftCorner); + destination = SpanSliceFrom(destination, downLeftCorner.Length); + + for (uint32_t i = 0; i < message.Length + 2; i++) + { + MemoryCopy(destination, horizontalLine); + destination = SpanSliceFrom(destination, horizontalLine.Length); + } + + MemoryCopy(destination, downRightCorner); + destination = SpanSliceFrom(destination, downRightCorner.Length); +} + +void KernelConsolePrintBoxMessage(ReadOnlySpanChar message) +{ + auto boxedMessage = StackAllocChar(512); + FormatBoxedMessage(boxedMessage, message); + KernelConsolePrint(String("\n%s\n"), boxedMessage); +} diff --git a/src/Kernel/KernelConsole.h b/src/Kernel/KernelConsole.h index f9de993..d8ca80a 100644 --- a/src/Kernel/KernelConsole.h +++ b/src/Kernel/KernelConsole.h @@ -4,5 +4,20 @@ #include "String.h" #include "Types.h" +const Color KernelConsoleColorNormal = { 212, 212, 212, 255 }; +const Color KernelConsoleColorHighlight = { 250, 250, 250, 255 }; +const Color KernelConsoleColorAccent = { 79, 193, 255, 255 }; +const Color KernelConsoleColorSuccess = { 106, 153, 85, 255 }; +const Color KernelConsoleColorWarning = { 255, 135, 100, 255 }; +const Color KernelConsoleColorError = { 255, 105, 105, 255 }; +const Color KernelConsoleColorInfo = { 220, 220, 170, 255 }; +const Color KernelConsoleColorAction = { 197, 134, 192, 255 }; +const Color KernelConsoleColorKeyword = { 86, 156, 214, 255 }; +const Color KernelConsoleColorNumeric = { 181, 206, 168, 255 }; + void KernelConsolePrint(ReadOnlySpanChar message, ...); +void KernelConsoleSetForegroundColor(Color color); +void KernelConsoleResetStyle(); + +void KernelConsolePrintBoxMessage(ReadOnlySpanChar message); diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 2096a75..035ee5e 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -33,20 +33,25 @@ void KernelTrapHandler(CpuTrapFrame* trapFrame) return; default: - KernelFailure(String("Unknown interrupt type. (InterruptType: %x)"), trapCause.InterruptType); + KernelFailure(String("Unknown interrupt type. (Code=%x, Extra=%x)"), trapCause.Code, trapCause.ExtraInformation); } } - KernelFailure(String("Unknown Kernel Trap Cause. (Cause=%x)"), trapCause.Type); + KernelFailure(String("Unknown kernel trap cause. (Code=%x, Extra=%x)"), trapCause.Code, trapCause.ExtraInformation); } void KernelMain() { auto platformInformation = PlatformGetInformation(); - KernelConsolePrint(String("\n\n\x1b[36m%s\x1b[0m\n"), KernelLogo); + KernelConsoleSetForegroundColor(KernelConsoleColorAccent); + KernelConsolePrint(String("\n\n%s\n"), KernelLogo); + KernelConsoleResetStyle(); + + KernelConsoleSetForegroundColor(KernelConsoleColorHighlight); KernelConsolePrint(String("Kanso OS %s "), KANSO_VERSION_FULL); KernelConsolePrint(String("(%s %d-bit)\n\n"), platformInformation.Name.Pointer, platformInformation.ArchitectureBits); + KernelConsoleResetStyle(); CpuSetTrapHandler(KernelTrapHandler); BiosSetTimer(CpuReadTime() + 10000000); diff --git a/src/Kernel/KernelTest.c b/src/Kernel/KernelTest.c index 07bdedd..8d7ef3d 100644 --- a/src/Kernel/KernelTest.c +++ b/src/Kernel/KernelTest.c @@ -5,33 +5,36 @@ #include "Platform.h" #include "Version.h" -const char* TEST_CONSOLE_RESET = "\x1b[0m"; -const char* TEST_CONSOLE_GREEN = "\x1b[32m"; -const char* TEST_CONSOLE_RED = "\x1b[31m"; - void KernelTestHandler(TestRunState state, ReadOnlySpanChar message, ...) { if (state == TestRunState_Start) { - KernelConsolePrint(String("%s[ RUN ]%s"), TEST_CONSOLE_GREEN, TEST_CONSOLE_RESET); + KernelConsoleSetForegroundColor(KernelConsoleColorSuccess); + KernelConsolePrint(String("[ RUN ]")); } else if (state == TestRunState_OK) { - KernelConsolePrint(String("%s[ OK ]%s"), TEST_CONSOLE_GREEN, TEST_CONSOLE_RESET); + KernelConsoleSetForegroundColor(KernelConsoleColorSuccess); + KernelConsolePrint(String("[ OK ]")); } else if (state == TestRunState_Passed) { - KernelConsolePrint(String("%s[ PASSED ]%s"), TEST_CONSOLE_GREEN, TEST_CONSOLE_RESET); + KernelConsoleSetForegroundColor(KernelConsoleColorSuccess); + KernelConsolePrint(String("[ PASSED ]")); } else if (state == TestRunState_Failed) { - KernelConsolePrint(String("%s[ FAILED ]%s"), TEST_CONSOLE_RED, TEST_CONSOLE_RESET); + KernelConsoleSetForegroundColor(KernelConsoleColorError); + KernelConsolePrint(String("[ FAILED ]")); } else if (state == TestRunState_Separator) { - KernelConsolePrint(String("%s[==========]%s"), TEST_CONSOLE_GREEN, TEST_CONSOLE_RESET); + KernelConsoleSetForegroundColor(KernelConsoleColorSuccess); + KernelConsolePrint(String("[==========]")); } + KernelConsoleResetStyle(); + va_list vargs; va_start(vargs, message); @@ -47,8 +50,10 @@ void KernelMain() { auto platformInformation = PlatformGetInformation(); + KernelConsoleSetForegroundColor(KernelConsoleColorHighlight); KernelConsolePrint(String("\n\nKanso OS Kernel Tests %s "), KANSO_VERSION_FULL); KernelConsolePrint(String("(%s %d-bit)\n\n"), platformInformation.Name.Pointer, platformInformation.ArchitectureBits); + KernelConsoleResetStyle(); TestRun(KernelTestHandler); BiosReset(BiosResetType_Shutdown, BiosResetReason_None); diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index b19f8d9..481eb2d 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -3,6 +3,10 @@ #include "Memory.h" #include "Types.h" +// -------------------------------------------------------------------------------------- +// General +// -------------------------------------------------------------------------------------- + typedef struct { ReadOnlySpanChar Name; @@ -11,6 +15,11 @@ typedef struct PlatformInformation PlatformGetInformation(); + +// -------------------------------------------------------------------------------------- +// Cpu +// -------------------------------------------------------------------------------------- + typedef enum { CpuInterruptType_None = 0, @@ -24,12 +33,21 @@ typedef enum { CpuTrapCauseType_Unknown, CpuTrapCauseType_Interrupt, + CpuTrapCauseType_Exception } CpuTrapCauseType; +typedef enum +{ + CpuExceptionCategory_Unknown +} CpuExceptionCategory; + typedef struct { CpuTrapCauseType Type; CpuInterruptType InterruptType; + CpuExceptionCategory ExceptionCategory; + uintptr_t Code; + uintptr_t ExtraInformation; } CpuTrapCause; struct CpuTrapFrame; @@ -55,6 +73,10 @@ uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame); void CpuTrapFrameSetProgramCounter(CpuTrapFrame* trapFrame, uintptr_t value); +// -------------------------------------------------------------------------------------- +// Bios +// -------------------------------------------------------------------------------------- + typedef enum { BiosResetType_Shutdown = 0, diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index 78eeccf..2add6da 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -1,3 +1,4 @@ +#include "Memory.h" #include "Types.h" #include "../../KernelConsole.h" #include "../../Platform.h" @@ -232,36 +233,103 @@ inline void CpuWaitForInterrupt() __asm__ __volatile__("wfi"); } +void LogRegister(ReadOnlySpanChar name, uintptr_t value, uint8_t padding, bool insertTab) +{ + // TODO: Color the register name with the keyword blue of VScode? + KernelConsoleSetForegroundColor(KernelConsoleColorKeyword); + KernelConsolePrint(String("%s"), name); + KernelConsoleResetStyle(); + + KernelConsolePrint(String(":")); + + for (uint32_t i = 0; i < padding; i++) + { + KernelConsolePrint(String(" ")); + } + + KernelConsoleSetForegroundColor(KernelConsoleColorNumeric); + KernelConsolePrint(String("%x"), value); + KernelConsoleResetStyle(); + + if (insertTab) + { + KernelConsolePrint(String(" ")); + } + else + { + KernelConsolePrint(String("\n")); + } +} + void LogGeneralPurposeRegisters(const GeneralPurposeRegisters* generalPurposeRegisters) { - KernelConsolePrint(String("ra: %x sp: %x gp: %x\n"), generalPurposeRegisters->RA, generalPurposeRegisters->SP, generalPurposeRegisters->GP); - KernelConsolePrint(String("tp: %x t0: %x t1: %x\n"), generalPurposeRegisters->TP, generalPurposeRegisters->T0, generalPurposeRegisters->T1); - KernelConsolePrint(String("t2: %x s0: %x s1: %x\n"), generalPurposeRegisters->T2, generalPurposeRegisters->S0, generalPurposeRegisters->S1); - KernelConsolePrint(String("a0: %x a1: %x a2: %x\n"), generalPurposeRegisters->A0, generalPurposeRegisters->A1, generalPurposeRegisters->A2); - KernelConsolePrint(String("a3: %x a4: %x a5: %x\n"), generalPurposeRegisters->A3, generalPurposeRegisters->A4, generalPurposeRegisters->A5); - KernelConsolePrint(String("a6: %x a7: %x s2: %x\n"), generalPurposeRegisters->A6, generalPurposeRegisters->A7, generalPurposeRegisters->S2); - KernelConsolePrint(String("s3: %x s4: %x s5: %x\n"), generalPurposeRegisters->S3, generalPurposeRegisters->S4, generalPurposeRegisters->S5); - KernelConsolePrint(String("s6: %x s7: %x s8: %x\n"), generalPurposeRegisters->S6, generalPurposeRegisters->S7, generalPurposeRegisters->S8); - KernelConsolePrint(String("s9: %x s10: %x s11: %x\n"), generalPurposeRegisters->S9, generalPurposeRegisters->S10, generalPurposeRegisters->S11); - KernelConsolePrint(String("t3: %x t4: %x t5: %x\n"), generalPurposeRegisters->T3, generalPurposeRegisters->T4, generalPurposeRegisters->T5); - KernelConsolePrint(String("t6: %x\n"), generalPurposeRegisters->T6); + LogRegister(String("ra"), generalPurposeRegisters->RA, 2, true); + LogRegister(String("sp"), generalPurposeRegisters->SP, 2, true); + LogRegister(String("gp"), generalPurposeRegisters->GP, 2, false); + + LogRegister(String("tp"), generalPurposeRegisters->TP, 2, true); + LogRegister(String("t0"), generalPurposeRegisters->T0, 2, true); + LogRegister(String("t1"), generalPurposeRegisters->T1, 2, false); + + LogRegister(String("t2"), generalPurposeRegisters->T2, 2, true); + LogRegister(String("s0"), generalPurposeRegisters->S0, 2, true); + LogRegister(String("s1"), generalPurposeRegisters->S1, 2, false); + + LogRegister(String("a0"), generalPurposeRegisters->A0, 2, true); + LogRegister(String("a1"), generalPurposeRegisters->A1, 2, true); + LogRegister(String("a2"), generalPurposeRegisters->A2, 2, false); + + LogRegister(String("a3"), generalPurposeRegisters->A3, 2, true); + LogRegister(String("a4"), generalPurposeRegisters->A4, 2, true); + LogRegister(String("a5"), generalPurposeRegisters->A5, 2, false); + + LogRegister(String("a6"), generalPurposeRegisters->A6, 2, true); + LogRegister(String("a7"), generalPurposeRegisters->A7, 2, true); + LogRegister(String("s2"), generalPurposeRegisters->S2, 2, false); + + LogRegister(String("s3"), generalPurposeRegisters->S3, 2, true); + LogRegister(String("s4"), generalPurposeRegisters->S4, 2, true); + LogRegister(String("s5"), generalPurposeRegisters->S5, 2, false); + + LogRegister(String("s6"), generalPurposeRegisters->S6, 2, true); + LogRegister(String("s7"), generalPurposeRegisters->S7, 2, true); + LogRegister(String("s8"), generalPurposeRegisters->S8, 2, false); + + LogRegister(String("s9"), generalPurposeRegisters->S9, 2, true); + LogRegister(String("s10"), generalPurposeRegisters->S10, 1, true); + LogRegister(String("s11"), generalPurposeRegisters->S11, 1, false); + + LogRegister(String("t3"), generalPurposeRegisters->T3, 2, true); + LogRegister(String("t4"), generalPurposeRegisters->T4, 2, true); + LogRegister(String("t5"), generalPurposeRegisters->T5, 2, false); + + LogRegister(String("t6"), generalPurposeRegisters->T6, 2, false); } void LogSupervisorRegisters(const SupervisorRegisters* supervisorRegisters) { - KernelConsolePrint(String("sepc: %x sstatus: %x sscratch: %x\n"), supervisorRegisters->Epc, supervisorRegisters->Status, supervisorRegisters->Scratch); - KernelConsolePrint(String("scause: %x stval: %x\n"), supervisorRegisters->Cause, supervisorRegisters->TrapValue); + LogRegister(String("sepc"), supervisorRegisters->Epc, 3, true); + LogRegister(String("sstatus"), supervisorRegisters->Status, 1, true); + LogRegister(String("sscratch"), supervisorRegisters->Scratch, 1, false); + + LogRegister(String("scause"), supervisorRegisters->Cause, 1, true); + LogRegister(String("stval"), supervisorRegisters->TrapValue, 3, false); } void CpuLogTrapFrame(const CpuTrapFrame* trapFrame) { - KernelConsolePrint(String("Trap Frame:\n")); - KernelConsolePrint(String("===========\n\n")); + KernelConsoleSetForegroundColor(KernelConsoleColorInfo); + KernelConsolePrintBoxMessage(String("Trap Frame")); + KernelConsoleResetStyle(); + KernelConsoleSetForegroundColor(KernelConsoleColorHighlight); KernelConsolePrint(String("General Purpose Registers:\n")); + KernelConsoleResetStyle(); LogGeneralPurposeRegisters(&trapFrame->GeneralPurposeRegisters); + KernelConsoleSetForegroundColor(KernelConsoleColorHighlight); KernelConsolePrint(String("\nSupervisor Registers:\n")); + KernelConsoleResetStyle(); LogSupervisorRegisters(&trapFrame->SupervisorRegisters); } @@ -274,7 +342,6 @@ CpuTrapCause CpuTrapFrameGetCause(const CpuTrapFrame* trapFrame) if (isInterrupt) { - // TODO: Extract constants switch (causeCode) { case RISCV_INTERRUPT_SOFTWARE: @@ -293,8 +360,10 @@ CpuTrapCause CpuTrapFrameGetCause(const CpuTrapFrame* trapFrame) return (CpuTrapCause) { - .Type = isInterrupt ? CpuTrapCauseType_Interrupt : CpuTrapCauseType_Unknown, - .InterruptType = interruptType + .Type = isInterrupt ? CpuTrapCauseType_Interrupt : CpuTrapCauseType_Exception, + .InterruptType = interruptType, + .Code = trapFrame->SupervisorRegisters.Cause, + .ExtraInformation = trapFrame->SupervisorRegisters.TrapValue }; /* diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index ae00b8c..dd38f8c 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -71,16 +71,15 @@ bool hasTestTrapHandler_WithInvalidInstructionRun = false; void TestTrapHandler_WithInvalidInstruction(CpuTrapFrame* trapFrame) { hasTestTrapHandler_WithInvalidInstructionRun = true; - CpuSetTrapHandler(nullptr); - - auto nextInstructionAddress = CpuComputeNextInstructionAddress(CpuTrapFrameGetProgramCounter(trapFrame)); - CpuTrapFrameSetProgramCounter(trapFrame, nextInstructionAddress); - // Assert auto trapCause = CpuTrapFrameGetCause(trapFrame); - TestAssertEquals(CpuTrapCauseType_Interrupt, trapCause.Type); + TestAssertEquals(CpuTrapCauseType_Exception, trapCause.Type); TestAssertEquals(CpuInterruptType_Timer, trapCause.InterruptType); + + auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); + auto nextInstructionAddress = CpuComputeNextInstructionAddress(programCounter); + CpuTrapFrameSetProgramCounter(trapFrame, nextInstructionAddress); } Test(Cpu, CpuTrapHandler_WithInvalidInstruction_HasCorrectCause) @@ -93,4 +92,6 @@ Test(Cpu, CpuTrapHandler_WithInvalidInstruction_HasCorrectCause) // Assert TestAssertEquals(true, hasTestTrapHandler_WithInvalidInstructionRun); + + CpuSetTrapHandler(nullptr); } From de831991f680fafbf0912576034e25f2e82d5fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Sat, 14 Jun 2025 19:56:58 +0200 Subject: [PATCH 09/11] Implement error codes for synchronous trap cause --- src/Kernel/KernelMain.c | 37 ++++++++++++++-- src/Kernel/Platform.h | 23 ++++++---- src/Kernel/Platforms/RiscV/Cpu.c | 72 +++++++++++++++++++++++++++----- tests/Kernel/CpuTests.c | 6 +-- 4 files changed, 112 insertions(+), 26 deletions(-) diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 035ee5e..452f3fb 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -14,10 +14,10 @@ const char KernelLogo[] = void KernelTrapHandler(CpuTrapFrame* trapFrame) { - CpuLogTrapFrame(trapFrame); auto trapCause = CpuTrapFrameGetCause(trapFrame); + auto errorName = String("Unknown kernel trap cause"); - if (trapCause.Type == CpuTrapCauseType_Interrupt) + if (trapCause.Type == CpuTrapType_Interrupt) { switch (trapCause.InterruptType) { @@ -33,11 +33,40 @@ void KernelTrapHandler(CpuTrapFrame* trapFrame) return; default: - KernelFailure(String("Unknown interrupt type. (Code=%x, Extra=%x)"), trapCause.Code, trapCause.ExtraInformation); + errorName = String("Unknown interrupt type"); + } + } + else + { + switch (trapCause.SynchronousType) + { + case CpuTrapSynchronousType_InstructionError: + errorName = String("Instruction error"); + break; + + case CpuTrapSynchronousType_AddressError: + errorName = String("Address error"); + break; + + case CpuTrapSynchronousType_PageError: + errorName = String("Page error"); + break; + + case CpuTrapSynchronousType_IntegrityError: + errorName = String("Integrity error"); + break; + + case CpuTrapSynchronousType_HardwareError: + errorName = String("Hardware error"); + break; + + default: + errorName = String("Unknown synchronous trap type"); } } - KernelFailure(String("Unknown kernel trap cause. (Code=%x, Extra=%x)"), trapCause.Code, trapCause.ExtraInformation); + CpuLogTrapFrame(trapFrame); + KernelFailure(String("%s. (Code=%x, Extra=%x)"), errorName, trapCause.Code, trapCause.ExtraInformation); } void KernelMain() diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index 481eb2d..c445db4 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -31,21 +31,28 @@ typedef enum typedef enum { - CpuTrapCauseType_Unknown, - CpuTrapCauseType_Interrupt, - CpuTrapCauseType_Exception -} CpuTrapCauseType; + CpuTrapType_Unknown, + CpuTrapType_Interrupt, + CpuTrapType_Synchronous +} CpuTrapType; typedef enum { - CpuExceptionCategory_Unknown -} CpuExceptionCategory; + CpuTrapSynchronousType_Unknown, + CpuTrapSynchronousType_InstructionError, + CpuTrapSynchronousType_Debug, + CpuTrapSynchronousType_AddressError, + CpuTrapSynchronousType_PageError, + CpuTrapSynchronousType_SystemCall, + CpuTrapSynchronousType_IntegrityError, + CpuTrapSynchronousType_HardwareError +} CpuTrapSynchronousType; typedef struct { - CpuTrapCauseType Type; + CpuTrapType Type; CpuInterruptType InterruptType; - CpuExceptionCategory ExceptionCategory; + CpuTrapSynchronousType SynchronousType; uintptr_t Code; uintptr_t ExtraInformation; } CpuTrapCause; diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index 2add6da..bcba663 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -7,6 +7,22 @@ #define RISCV_INTERRUPT_TIMER 5 #define RISCV_INTERRUPT_EXTERNAL 9 +#define RISCV_TRAP_SYNCHRONOUS_INSTRUCTION_ADDRESS_MISALIGNED 0 +#define RISCV_TRAP_SYNCHRONOUS_INSTRUCTION_ACCESS_FAULT 1 +#define RISCV_TRAP_SYNCHRONOUS_ILLEGAL_INSTRUCTION 2 +#define RISCV_TRAP_SYNCHRONOUS_BREAKPOINT 3 +#define RISCV_TRAP_LOAD_ADDRESS_MISALIGNED 4 +#define RISCV_TRAP_LOAD_ACCESS_FAULT 5 +#define RISCV_TRAP_STORE_AMO_ADDRESS_MISALIGNED 6 +#define RISCV_TRAP_STORE_AMO_ACCESS_FAULT 7 +#define RISCV_TRAP_ECALL_FROM_USER_MODE 8 +#define RISCV_TRAP_ECALL_FROM_SUPERVISOR_MODE 9 +#define RISCV_TRAP_INSTRUCTION_PAGE_FAULT 12 +#define RISCV_TRAP_LOAD_PAGE_FAULT 13 +#define RISCV_TRAP_STORE_AMO_PAGE_FAULT 15 +#define RISCV_TRAP_SOFTWARE_CHECK 18 +#define RISCV_TRAP_HARDWARE_ERROR 19 + typedef struct { uintptr_t RA; @@ -339,6 +355,7 @@ CpuTrapCause CpuTrapFrameGetCause(const CpuTrapFrame* trapFrame) auto causeCode = trapFrame->SupervisorRegisters.Cause & ((1ULL<<((sizeof(uintptr_t)*8)-1))-1); auto interruptType = CpuInterruptType_None; + auto synchronousType = CpuTrapSynchronousType_Unknown; if (isInterrupt) { @@ -357,24 +374,57 @@ CpuTrapCause CpuTrapFrameGetCause(const CpuTrapFrame* trapFrame) break; } } + + else + { + switch (causeCode) + { + case RISCV_TRAP_SYNCHRONOUS_INSTRUCTION_ADDRESS_MISALIGNED: + case RISCV_TRAP_SYNCHRONOUS_INSTRUCTION_ACCESS_FAULT: + case RISCV_TRAP_SYNCHRONOUS_ILLEGAL_INSTRUCTION: + synchronousType = CpuTrapSynchronousType_InstructionError; + break; + + case RISCV_TRAP_SYNCHRONOUS_BREAKPOINT: + synchronousType = CpuTrapSynchronousType_Debug; + break; + + case RISCV_TRAP_LOAD_ADDRESS_MISALIGNED: + case RISCV_TRAP_LOAD_ACCESS_FAULT: + case RISCV_TRAP_STORE_AMO_ADDRESS_MISALIGNED: + case RISCV_TRAP_STORE_AMO_ACCESS_FAULT: + synchronousType = CpuTrapSynchronousType_AddressError; + break; + + case RISCV_TRAP_ECALL_FROM_USER_MODE: + case RISCV_TRAP_ECALL_FROM_SUPERVISOR_MODE: + synchronousType = CpuTrapSynchronousType_SystemCall; + break; + + case RISCV_TRAP_INSTRUCTION_PAGE_FAULT: + case RISCV_TRAP_LOAD_PAGE_FAULT: + case RISCV_TRAP_STORE_AMO_PAGE_FAULT: + synchronousType = CpuTrapSynchronousType_PageError; + break; + + case RISCV_TRAP_SOFTWARE_CHECK: + synchronousType = CpuTrapSynchronousType_IntegrityError; + break; + + case RISCV_TRAP_HARDWARE_ERROR: + synchronousType = CpuTrapSynchronousType_HardwareError; + break; + } + } return (CpuTrapCause) { - .Type = isInterrupt ? CpuTrapCauseType_Interrupt : CpuTrapCauseType_Exception, + .Type = isInterrupt ? CpuTrapType_Interrupt : CpuTrapType_Synchronous, .InterruptType = interruptType, + .SynchronousType = synchronousType, .Code = trapFrame->SupervisorRegisters.Cause, .ExtraInformation = trapFrame->SupervisorRegisters.TrapValue }; - - /* - switch (code) { - case 8: return TC_SYSCALL; - case 12: return TC_PAGE_FAULT_INS; - case 13: return TC_PAGE_FAULT_LOAD; - case 15: return TC_PAGE_FAULT_STORE; - case 2: return TC_ILLEGAL_INSTRUCTION; - default: return TC_OTHER; - }*/ } inline uintptr_t CpuTrapFrameGetProgramCounter(const CpuTrapFrame* trapFrame) diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index dd38f8c..0f2abdb 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -48,7 +48,7 @@ void TestTrapHandler_WithTimerInterrupt(CpuTrapFrame* trapFrame) auto trapCause = CpuTrapFrameGetCause(trapFrame); - TestAssertEquals(CpuTrapCauseType_Interrupt, trapCause.Type); + TestAssertEquals(CpuTrapType_Interrupt, trapCause.Type); TestAssertEquals(CpuInterruptType_Timer, trapCause.InterruptType); } @@ -74,8 +74,8 @@ void TestTrapHandler_WithInvalidInstruction(CpuTrapFrame* trapFrame) auto trapCause = CpuTrapFrameGetCause(trapFrame); - TestAssertEquals(CpuTrapCauseType_Exception, trapCause.Type); - TestAssertEquals(CpuInterruptType_Timer, trapCause.InterruptType); + TestAssertEquals(CpuTrapType_Synchronous, trapCause.Type); + TestAssertEquals(CpuTrapSynchronousType_InstructionError, trapCause.SynchronousType); auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); auto nextInstructionAddress = CpuComputeNextInstructionAddress(programCounter); From 79f197eb15567f7a6bc6137d0ff9d6c59478108f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Sat, 14 Jun 2025 22:31:09 +0200 Subject: [PATCH 10/11] Fix test --- src/Common/Test.h | 1 + src/Kernel/Platforms/RiscV/Cpu.c | 2 +- tests/Kernel/CpuTests.c | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Common/Test.h b/src/Common/Test.h index 5621d58..556c54c 100644 --- a/src/Common/Test.h +++ b/src/Common/Test.h @@ -62,6 +62,7 @@ extern SpanChar globalTestLastErrorMessage; #define TestAssertEquals(expected, actual) TestAssertCore((expected) == (actual), expected, actual, "==") #define TestAssertNotEquals(expected, actual) TestAssertCore((expected) != (actual), expected, actual, "!=") #define TestAssertGreaterThan(expected, actual) TestAssertCore((expected) > (actual), expected, actual, ">") +#define TestAssertIsTrue(actual) TestAssertCore(true == (actual), true, actual, "==") // TODO: Adapt the macro like the core one #define TestAssertStringEquals(expected, actual) \ diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index bcba663..c72409a 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -246,7 +246,7 @@ inline void CpuClearPendingInterrupts(CpuInterruptType types) inline void CpuWaitForInterrupt() { - __asm__ __volatile__("wfi"); + __asm__ __volatile__("wfi" ::: "memory"); } void LogRegister(ReadOnlySpanChar name, uintptr_t value, uint8_t padding, bool insertTab) diff --git a/tests/Kernel/CpuTests.c b/tests/Kernel/CpuTests.c index 0f2abdb..3b200c4 100644 --- a/tests/Kernel/CpuTests.c +++ b/tests/Kernel/CpuTests.c @@ -36,7 +36,7 @@ Test(Cpu, CpuReadCycle) TestAssertGreaterThan(cycle2, cycle1); } -bool hasTestTrapHandler_WithTimerInterruptRun = false; +volatile bool hasTestTrapHandler_WithTimerInterruptRun = false; void TestTrapHandler_WithTimerInterrupt(CpuTrapFrame* trapFrame) { @@ -57,13 +57,21 @@ Test(Cpu, CpuTrapHandler_WithTimerInterrupt_HasCorrectCause) // Arrange CpuSetTrapHandler(TestTrapHandler_WithTimerInterrupt); CpuEnableInterrupts(CpuInterruptType_Timer); + auto timerDeadline = CpuReadTime(); // Act - BiosSetTimer(CpuReadTime()); + BiosSetTimer(timerDeadline); // Assert - // TODO: AssertIsTrue - TestAssertEquals(true, hasTestTrapHandler_WithTimerInterruptRun); + const uint32_t maxIterations = 10; + uint32_t iterations = 0; + + while (!hasTestTrapHandler_WithTimerInterruptRun && iterations < maxIterations) + { + iterations++; + } + + TestAssertIsTrue(hasTestTrapHandler_WithTimerInterruptRun); } bool hasTestTrapHandler_WithInvalidInstructionRun = false; From 661a6430a99723adec25068c3fb237600c7326df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Sun, 15 Jun 2025 07:24:27 +0200 Subject: [PATCH 11/11] Fix CI workflow --- .github/workflows/kanso-ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/kanso-ci.yml b/.github/workflows/kanso-ci.yml index 4825e24..5344fc3 100644 --- a/.github/workflows/kanso-ci.yml +++ b/.github/workflows/kanso-ci.yml @@ -31,3 +31,16 @@ jobs: with: platform: ${{ matrix.Platform }} + results: + if: ${{ always() }} + runs-on: ubuntu-latest + name: Final Results + needs: [kernel-build] + steps: + - run: | + result="${{ needs.kernel-build.result }}" + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi