From f0acad6f3206079d804b2f59aace0dc32dbeb6dc Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Thu, 19 Feb 2026 08:14:48 +0100 Subject: kernel: lots of tweaks and improvements, WIP: ASN, FileMgr support for OpenHeFS. Signed-off-by: Amlal El Mahrouss --- src/kernel/HALKit/AMD64/CxxAbi.cc | 77 --- src/kernel/HALKit/AMD64/CxxAbi.cpp | 77 +++ src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc | 111 ---- .../HALKit/AMD64/HalACPIFactoryInterface.cpp | 111 ++++ src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc | 37 -- src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cpp | 37 ++ src/kernel/HALKit/AMD64/HalApplicationProcessor.cc | 218 -------- .../HALKit/AMD64/HalApplicationProcessor.cpp | 218 ++++++++ src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc | 177 ------- .../HALKit/AMD64/HalCoreInterruptHandler.cpp | 177 +++++++ src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cc | 7 - src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cpp | 7 + .../HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cc | 7 - .../HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cpp | 7 + src/kernel/HALKit/AMD64/HalDebugOutput.cc | 225 -------- src/kernel/HALKit/AMD64/HalDebugOutput.cpp | 225 ++++++++ src/kernel/HALKit/AMD64/HalDebugProtocol.cc | 11 - src/kernel/HALKit/AMD64/HalDebugProtocol.cpp | 11 + src/kernel/HALKit/AMD64/HalDescriptorLoader.cc | 69 --- src/kernel/HALKit/AMD64/HalDescriptorLoader.cpp | 69 +++ src/kernel/HALKit/AMD64/HalKernelMain.cc | 164 ------ src/kernel/HALKit/AMD64/HalKernelMain.cpp | 164 ++++++ src/kernel/HALKit/AMD64/HalKernelPanic.cc | 56 -- src/kernel/HALKit/AMD64/HalKernelPanic.cpp | 56 ++ src/kernel/HALKit/AMD64/HalPagingMgr.cc | 162 ------ src/kernel/HALKit/AMD64/HalPagingMgr.cpp | 162 ++++++ src/kernel/HALKit/AMD64/HalProcessor.cc | 84 --- src/kernel/HALKit/AMD64/HalProcessor.cpp | 84 +++ .../HALKit/AMD64/HalSchedulerCorePrimitives.cc | 49 -- .../HALKit/AMD64/HalSchedulerCorePrimitives.cpp | 49 ++ src/kernel/HALKit/AMD64/HalTimer.cc | 92 ---- src/kernel/HALKit/AMD64/HalTimer.cpp | 92 ++++ .../HALKit/AMD64/Network/Generic+Basic+RTL8139.cc | 127 ----- .../HALKit/AMD64/Network/Generic+Basic+RTL8139.cpp | 127 +++++ src/kernel/HALKit/AMD64/PCI/DMA.cc | 70 --- src/kernel/HALKit/AMD64/PCI/DMA.cpp | 70 +++ src/kernel/HALKit/AMD64/PCI/Database.cc | 7 - src/kernel/HALKit/AMD64/PCI/Database.cpp | 7 + src/kernel/HALKit/AMD64/PCI/Device.cc | 140 ----- src/kernel/HALKit/AMD64/PCI/Device.cpp | 140 +++++ src/kernel/HALKit/AMD64/PCI/Express.cc | 7 - src/kernel/HALKit/AMD64/PCI/Express.cpp | 7 + src/kernel/HALKit/AMD64/PCI/IO.cc | 5 - src/kernel/HALKit/AMD64/PCI/IO.cpp | 5 + src/kernel/HALKit/AMD64/PCI/Iterator.cc | 28 - src/kernel/HALKit/AMD64/PCI/Iterator.cpp | 28 + src/kernel/HALKit/AMD64/PCI/PCI.cc | 5 - src/kernel/HALKit/AMD64/PCI/PCI.cpp | 5 + src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 588 --------------------- src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cpp | 588 +++++++++++++++++++++ src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc | 184 ------- src/kernel/HALKit/AMD64/Storage/DMA+Generic.cpp | 184 +++++++ src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc | 7 - src/kernel/HALKit/AMD64/Storage/NVME+Generic.cpp | 7 + src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc | 262 --------- src/kernel/HALKit/AMD64/Storage/PIO+Generic.cpp | 262 +++++++++ src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cc | 11 - src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cpp | 11 + src/kernel/HALKit/ARM64/APM/APM+IO.cc | 33 -- src/kernel/HALKit/ARM64/APM/APM+IO.cpp | 33 ++ src/kernel/HALKit/ARM64/CxxAbi.cc | 85 --- src/kernel/HALKit/ARM64/CxxAbi.cpp | 85 +++ src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc | 24 - .../HALKit/ARM64/HalACPIFactoryInterface.cpp | 24 + src/kernel/HALKit/ARM64/HalApplicationProcessor.cc | 138 ----- .../HALKit/ARM64/HalApplicationProcessor.cpp | 138 +++++ src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc | 156 ------ .../HALKit/ARM64/HalCoreInterruptHandler.cpp | 156 ++++++ src/kernel/HALKit/ARM64/HalDebugOutput.cc | 69 --- src/kernel/HALKit/ARM64/HalDebugOutput.cpp | 69 +++ src/kernel/HALKit/ARM64/HalKernelMain.cc | 60 --- src/kernel/HALKit/ARM64/HalKernelMain.cpp | 60 +++ src/kernel/HALKit/ARM64/HalKernelPanic.cc | 52 -- src/kernel/HALKit/ARM64/HalKernelPanic.cpp | 52 ++ src/kernel/HALKit/ARM64/HalPagingMgr.cc | 81 --- src/kernel/HALKit/ARM64/HalPagingMgr.cpp | 81 +++ src/kernel/HALKit/ARM64/HalSchedulerCore.cc | 19 - src/kernel/HALKit/ARM64/HalSchedulerCore.cpp | 19 + .../HALKit/ARM64/HalSchedulerCorePrimitives.cc | 28 - .../HALKit/ARM64/HalSchedulerCorePrimitives.cpp | 28 + src/kernel/HALKit/ARM64/HalTimer.cc | 6 - src/kernel/HALKit/ARM64/HalTimer.cpp | 6 + src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cc | 11 - src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cpp | 11 + src/kernel/HALKit/ARM64/Storage/UFS+Generic.cc | 3 - src/kernel/HALKit/ARM64/Storage/UFS+Generic.cpp | 3 + src/kernel/HALKit/POWER/HalApplicationProcessor.cc | 40 -- .../HALKit/POWER/HalApplicationProcessor.cpp | 40 ++ src/kernel/HALKit/POWER/HalDebugOutput.cc | 22 - src/kernel/HALKit/POWER/HalDebugOutput.cpp | 22 + src/kernel/HALKit/POWER/HalHardwareThread.cc | 6 - src/kernel/HALKit/POWER/HalHardwareThread.cpp | 6 + src/kernel/HALKit/POWER/HalVirtualMemory.cc | 44 -- src/kernel/HALKit/POWER/HalVirtualMemory.cpp | 44 ++ src/kernel/HALKit/RISCV/HalApplicationProcessor.cc | 37 -- .../HALKit/RISCV/HalApplicationProcessor.cpp | 37 ++ 96 files changed, 3901 insertions(+), 3901 deletions(-) delete mode 100644 src/kernel/HALKit/AMD64/CxxAbi.cc create mode 100644 src/kernel/HALKit/AMD64/CxxAbi.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc create mode 100644 src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc create mode 100644 src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalApplicationProcessor.cc create mode 100644 src/kernel/HALKit/AMD64/HalApplicationProcessor.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc create mode 100644 src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cc create mode 100644 src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cc create mode 100644 src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalDebugOutput.cc create mode 100644 src/kernel/HALKit/AMD64/HalDebugOutput.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalDebugProtocol.cc create mode 100644 src/kernel/HALKit/AMD64/HalDebugProtocol.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalDescriptorLoader.cc create mode 100644 src/kernel/HALKit/AMD64/HalDescriptorLoader.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalKernelMain.cc create mode 100644 src/kernel/HALKit/AMD64/HalKernelMain.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalKernelPanic.cc create mode 100644 src/kernel/HALKit/AMD64/HalKernelPanic.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalPagingMgr.cc create mode 100644 src/kernel/HALKit/AMD64/HalPagingMgr.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalProcessor.cc create mode 100644 src/kernel/HALKit/AMD64/HalProcessor.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc create mode 100644 src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cpp delete mode 100644 src/kernel/HALKit/AMD64/HalTimer.cc create mode 100644 src/kernel/HALKit/AMD64/HalTimer.cpp delete mode 100644 src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc create mode 100644 src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/DMA.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/DMA.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/Database.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/Database.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/Device.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/Device.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/Express.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/Express.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/IO.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/IO.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/Iterator.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/Iterator.cpp delete mode 100644 src/kernel/HALKit/AMD64/PCI/PCI.cc create mode 100644 src/kernel/HALKit/AMD64/PCI/PCI.cpp delete mode 100644 src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc create mode 100644 src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cpp delete mode 100644 src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc create mode 100644 src/kernel/HALKit/AMD64/Storage/DMA+Generic.cpp delete mode 100644 src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc create mode 100644 src/kernel/HALKit/AMD64/Storage/NVME+Generic.cpp delete mode 100644 src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc create mode 100644 src/kernel/HALKit/AMD64/Storage/PIO+Generic.cpp delete mode 100644 src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cc create mode 100644 src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cpp delete mode 100644 src/kernel/HALKit/ARM64/APM/APM+IO.cc create mode 100644 src/kernel/HALKit/ARM64/APM/APM+IO.cpp delete mode 100644 src/kernel/HALKit/ARM64/CxxAbi.cc create mode 100644 src/kernel/HALKit/ARM64/CxxAbi.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc create mode 100644 src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalApplicationProcessor.cc create mode 100644 src/kernel/HALKit/ARM64/HalApplicationProcessor.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc create mode 100644 src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalDebugOutput.cc create mode 100644 src/kernel/HALKit/ARM64/HalDebugOutput.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalKernelMain.cc create mode 100644 src/kernel/HALKit/ARM64/HalKernelMain.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalKernelPanic.cc create mode 100644 src/kernel/HALKit/ARM64/HalKernelPanic.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalPagingMgr.cc create mode 100644 src/kernel/HALKit/ARM64/HalPagingMgr.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalSchedulerCore.cc create mode 100644 src/kernel/HALKit/ARM64/HalSchedulerCore.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cc create mode 100644 src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cpp delete mode 100644 src/kernel/HALKit/ARM64/HalTimer.cc create mode 100644 src/kernel/HALKit/ARM64/HalTimer.cpp delete mode 100644 src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cc create mode 100644 src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cpp delete mode 100644 src/kernel/HALKit/ARM64/Storage/UFS+Generic.cc create mode 100644 src/kernel/HALKit/ARM64/Storage/UFS+Generic.cpp delete mode 100644 src/kernel/HALKit/POWER/HalApplicationProcessor.cc create mode 100644 src/kernel/HALKit/POWER/HalApplicationProcessor.cpp delete mode 100644 src/kernel/HALKit/POWER/HalDebugOutput.cc create mode 100644 src/kernel/HALKit/POWER/HalDebugOutput.cpp delete mode 100644 src/kernel/HALKit/POWER/HalHardwareThread.cc create mode 100644 src/kernel/HALKit/POWER/HalHardwareThread.cpp delete mode 100644 src/kernel/HALKit/POWER/HalVirtualMemory.cc create mode 100644 src/kernel/HALKit/POWER/HalVirtualMemory.cpp delete mode 100644 src/kernel/HALKit/RISCV/HalApplicationProcessor.cc create mode 100644 src/kernel/HALKit/RISCV/HalApplicationProcessor.cpp (limited to 'src/kernel/HALKit') diff --git a/src/kernel/HALKit/AMD64/CxxAbi.cc b/src/kernel/HALKit/AMD64/CxxAbi.cc deleted file mode 100644 index f0f18266..00000000 --- a/src/kernel/HALKit/AMD64/CxxAbi.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include - -atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; - -uarch_t __atexit_func_count; - -/// @brief dynamic shared object Handle. -Kernel::UIntPtr __dso_handle; - -EXTERN_C Kernel::Void __cxa_pure_virtual(void* self) { - (Kernel::Void)(Kernel::kout << "object: " - << Kernel::number(reinterpret_cast(self))); - (Kernel::Void)(Kernel::kout << ", has unimplemented virtual functions.\r"); -} - -EXTERN_C void ___chkstk_ms(PtrDiff frame_size) { - char* sp; - asm volatile("mov %%rsp, %0" : "=r"(sp)); - - for (PtrDiff offset = kPageSize; offset < frame_size; offset += kPageSize) { - sp[-offset] = 0; - } -} - -EXTERN_C int atexit(void (*f)()) { - if (__atexit_func_count >= kAtExitMacDestructors) return 1; - - __atexit_funcs[__atexit_func_count].destructor_func = f; - - __atexit_func_count++; - - return 0; -} - -EXTERN_C void __cxa_finalize(void* f) { - uarch_t i = __atexit_func_count; - if (!f) { - while (i--) { - if (__atexit_funcs[i].destructor_func) { - (*__atexit_funcs[i].destructor_func)(); - }; - } - - return; - } - - while (i--) { - if (__atexit_funcs[i].destructor_func) { - (*__atexit_funcs[i].destructor_func)(); - __atexit_funcs[i].destructor_func = 0; - }; - } -} - -namespace cxxabiv1 { -EXTERN_C int __cxa_guard_acquire(__guard g) { - if ((*g & 1) || (*g & 2)) return 1; - *g |= 2; - return 0; -} - -EXTERN_C void __cxa_guard_release(__guard g) { - *g |= 1; - *g &= 2; -} - -EXTERN_C void __cxa_guard_abort(__guard g) { - *g &= ~2; -} -} // namespace cxxabiv1 diff --git a/src/kernel/HALKit/AMD64/CxxAbi.cpp b/src/kernel/HALKit/AMD64/CxxAbi.cpp new file mode 100644 index 00000000..f0f18266 --- /dev/null +++ b/src/kernel/HALKit/AMD64/CxxAbi.cpp @@ -0,0 +1,77 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include + +atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; + +uarch_t __atexit_func_count; + +/// @brief dynamic shared object Handle. +Kernel::UIntPtr __dso_handle; + +EXTERN_C Kernel::Void __cxa_pure_virtual(void* self) { + (Kernel::Void)(Kernel::kout << "object: " + << Kernel::number(reinterpret_cast(self))); + (Kernel::Void)(Kernel::kout << ", has unimplemented virtual functions.\r"); +} + +EXTERN_C void ___chkstk_ms(PtrDiff frame_size) { + char* sp; + asm volatile("mov %%rsp, %0" : "=r"(sp)); + + for (PtrDiff offset = kPageSize; offset < frame_size; offset += kPageSize) { + sp[-offset] = 0; + } +} + +EXTERN_C int atexit(void (*f)()) { + if (__atexit_func_count >= kAtExitMacDestructors) return 1; + + __atexit_funcs[__atexit_func_count].destructor_func = f; + + __atexit_func_count++; + + return 0; +} + +EXTERN_C void __cxa_finalize(void* f) { + uarch_t i = __atexit_func_count; + if (!f) { + while (i--) { + if (__atexit_funcs[i].destructor_func) { + (*__atexit_funcs[i].destructor_func)(); + }; + } + + return; + } + + while (i--) { + if (__atexit_funcs[i].destructor_func) { + (*__atexit_funcs[i].destructor_func)(); + __atexit_funcs[i].destructor_func = 0; + }; + } +} + +namespace cxxabiv1 { +EXTERN_C int __cxa_guard_acquire(__guard g) { + if ((*g & 1) || (*g & 2)) return 1; + *g |= 2; + return 0; +} + +EXTERN_C void __cxa_guard_release(__guard g) { + *g |= 1; + *g &= 2; +} + +EXTERN_C void __cxa_guard_abort(__guard g) { + *g &= ~2; +} +} // namespace cxxabiv1 diff --git a/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc b/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc deleted file mode 100644 index 7368ea10..00000000 --- a/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include - -namespace Kernel { -namespace Detail { - struct FADT final : public SDT { - UInt32 FirmwareCtrl; - UInt32 Dsdt; - - // field used in ACPI 1.0; no longer in use, for compatibility only - UInt8 Reserved; - - UInt8 PreferredPowerManagementProfile; - UInt16 SCI_Interrupt; - UInt32 SMI_CommandPort; - UInt8 AcpiEnable; - UInt8 AcpiDisable; - UInt8 S4BIOS_REQ; - UInt8 PSTATE_Control; - UInt32 PM1aEventBlock; - UInt32 PM1bEventBlock; - UInt32 PM1aControlBlock; - UInt32 PM1bControlBlock; - UInt32 PM2ControlBlock; - UInt32 PMTimerBlock; - UInt32 GPE0Block; - UInt32 GPE1Block; - UInt8 PM1EventLength; - UInt8 PM1ControlLength; - UInt8 PM2ControlLength; - UInt8 PMTimerLength; - UInt8 GPE0Length; - UInt8 GPE1Length; - UInt8 GPE1Base; - UInt8 CStateControl; - UInt16 WorstC2Latency; - UInt16 WorstC3Latency; - UInt16 FlushSize; - UInt16 FlushStride; - UInt8 DutyOffset; - UInt8 DutyWidth; - UInt8 DayAlarm; - UInt8 MonthAlarm; - UInt8 Century; - - // reserved in ACPI 1.0; used since ACPI 2.0+ - UInt16 BootArchitecturkMMFlags; - - UInt8 Reserved2; - UInt32 Flags; - - // 12 byte structure; see below for details - ACPI_ADDRESS ResetReg; - - UInt8 ResetValue; - UInt8 Reserved3[3]; - - // 64bit pointers - Available on ACPI 2.0+ - UInt64 X_FirmwareControl; - UInt64 X_Dsdt; - - ACPI_ADDRESS X_PM1aEventBlock; - ACPI_ADDRESS X_PM1bEventBlock; - ACPI_ADDRESS X_PM1aControlBlock; - ACPI_ADDRESS X_PM1bControlBlock; - ACPI_ADDRESS X_PM2ControlBlock; - ACPI_ADDRESS X_PMTimerBlock; - ACPI_ADDRESS X_GPE0Block; - ACPI_ADDRESS X_GPE1Block; - }; -} // namespace Detail - -ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) : fRsdp(rsp_ptr), fEntries(0) {} - -Bool ACPIFactoryInterface::Shutdown() { - return NO; -} - -/// @brief Reboot machine in either ACPI or by triple faulting. -/// @return nothing it's a reboot. -Void ACPIFactoryInterface::Reboot() { - asm volatile( - ".intel_syntax noprefix; " - "rt_reset_hardware:; " - "cli; " - "wait_gate1: ; " - "in al,0x64 ; " - "and al,2 ; " - "jnz wait_gate1 ; " - "mov al,0x0D1 ; " - "out 0x64,al ; " - "wait_gate2: ; " - "in al,0x64 ; " - "and al,2 ; " - "jnz wait_gate2 ; " - "mov al,0x0FE ; " - "out 0x60,al ; " - "xor rax,rax ; " - "lidt [rax] ; " - "reset_wait: ; " - "jmp reset_wait ; " - ".att_syntax; "); -} -} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cpp b/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cpp new file mode 100644 index 00000000..7368ea10 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cpp @@ -0,0 +1,111 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include + +namespace Kernel { +namespace Detail { + struct FADT final : public SDT { + UInt32 FirmwareCtrl; + UInt32 Dsdt; + + // field used in ACPI 1.0; no longer in use, for compatibility only + UInt8 Reserved; + + UInt8 PreferredPowerManagementProfile; + UInt16 SCI_Interrupt; + UInt32 SMI_CommandPort; + UInt8 AcpiEnable; + UInt8 AcpiDisable; + UInt8 S4BIOS_REQ; + UInt8 PSTATE_Control; + UInt32 PM1aEventBlock; + UInt32 PM1bEventBlock; + UInt32 PM1aControlBlock; + UInt32 PM1bControlBlock; + UInt32 PM2ControlBlock; + UInt32 PMTimerBlock; + UInt32 GPE0Block; + UInt32 GPE1Block; + UInt8 PM1EventLength; + UInt8 PM1ControlLength; + UInt8 PM2ControlLength; + UInt8 PMTimerLength; + UInt8 GPE0Length; + UInt8 GPE1Length; + UInt8 GPE1Base; + UInt8 CStateControl; + UInt16 WorstC2Latency; + UInt16 WorstC3Latency; + UInt16 FlushSize; + UInt16 FlushStride; + UInt8 DutyOffset; + UInt8 DutyWidth; + UInt8 DayAlarm; + UInt8 MonthAlarm; + UInt8 Century; + + // reserved in ACPI 1.0; used since ACPI 2.0+ + UInt16 BootArchitecturkMMFlags; + + UInt8 Reserved2; + UInt32 Flags; + + // 12 byte structure; see below for details + ACPI_ADDRESS ResetReg; + + UInt8 ResetValue; + UInt8 Reserved3[3]; + + // 64bit pointers - Available on ACPI 2.0+ + UInt64 X_FirmwareControl; + UInt64 X_Dsdt; + + ACPI_ADDRESS X_PM1aEventBlock; + ACPI_ADDRESS X_PM1bEventBlock; + ACPI_ADDRESS X_PM1aControlBlock; + ACPI_ADDRESS X_PM1bControlBlock; + ACPI_ADDRESS X_PM2ControlBlock; + ACPI_ADDRESS X_PMTimerBlock; + ACPI_ADDRESS X_GPE0Block; + ACPI_ADDRESS X_GPE1Block; + }; +} // namespace Detail + +ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) : fRsdp(rsp_ptr), fEntries(0) {} + +Bool ACPIFactoryInterface::Shutdown() { + return NO; +} + +/// @brief Reboot machine in either ACPI or by triple faulting. +/// @return nothing it's a reboot. +Void ACPIFactoryInterface::Reboot() { + asm volatile( + ".intel_syntax noprefix; " + "rt_reset_hardware:; " + "cli; " + "wait_gate1: ; " + "in al,0x64 ; " + "and al,2 ; " + "jnz wait_gate1 ; " + "mov al,0x0D1 ; " + "out 0x64,al ; " + "wait_gate2: ; " + "in al,0x64 ; " + "and al,2 ; " + "jnz wait_gate2 ; " + "mov al,0x0FE ; " + "out 0x60,al ; " + "xor rax,rax ; " + "lidt [rax] ; " + "reset_wait: ; " + "jmp reset_wait ; " + ".att_syntax; "); +} +} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc b/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc deleted file mode 100644 index b262f2b3..00000000 --- a/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -namespace Kernel::HAL { -/***********************************************************************************/ -/// Constructors. -/***********************************************************************************/ -LAPICDmaWrapper::LAPICDmaWrapper(VoidPtr base) : fApic(base) {} -LAPICDmaWrapper::~LAPICDmaWrapper() = default; - -/***********************************************************************************/ -/// @brief Read from APIC controller. -/// @param reg register. -/***********************************************************************************/ -UInt32 LAPICDmaWrapper::Read(UInt16 reg) { - MUST_PASS(this->fApic); - - UInt32 volatile* io_apic = (UInt32 volatile*) this->fApic; - return io_apic[reg]; -} - -/***********************************************************************************/ -/// @brief Write to APIC controller. -/// @param reg register. -/// @param value value. -/***********************************************************************************/ -Void LAPICDmaWrapper::Write(UInt16 reg, UInt32 value) { - MUST_PASS(this->fApic); - - UInt32 volatile* io_apic = (UInt32 volatile*) this->fApic; - io_apic[reg] = value; -} -} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cpp b/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cpp new file mode 100644 index 00000000..b262f2b3 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cpp @@ -0,0 +1,37 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +namespace Kernel::HAL { +/***********************************************************************************/ +/// Constructors. +/***********************************************************************************/ +LAPICDmaWrapper::LAPICDmaWrapper(VoidPtr base) : fApic(base) {} +LAPICDmaWrapper::~LAPICDmaWrapper() = default; + +/***********************************************************************************/ +/// @brief Read from APIC controller. +/// @param reg register. +/***********************************************************************************/ +UInt32 LAPICDmaWrapper::Read(UInt16 reg) { + MUST_PASS(this->fApic); + + UInt32 volatile* io_apic = (UInt32 volatile*) this->fApic; + return io_apic[reg]; +} + +/***********************************************************************************/ +/// @brief Write to APIC controller. +/// @param reg register. +/// @param value value. +/***********************************************************************************/ +Void LAPICDmaWrapper::Write(UInt16 reg, UInt32 value) { + MUST_PASS(this->fApic); + + UInt32 volatile* io_apic = (UInt32 volatile*) this->fApic; + io_apic[reg] = value; +} +} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalApplicationProcessor.cc b/src/kernel/HALKit/AMD64/HalApplicationProcessor.cc deleted file mode 100644 index 0450c71c..00000000 --- a/src/kernel/HALKit/AMD64/HalApplicationProcessor.cc +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#define APIC_MAG "APIC" - -#define APIC_ICR_LOW 0x300 -#define APIC_ICR_HIGH 0x310 -#define APIC_SIPI_VEC 0x00500 -#define APIC_EIPI_VEC 0x00400 - -#define LAPIC_REG_TIMER_LVT 0x320 -#define LAPIC_REG_TIMER_INITCNT 0x380 -#define LAPIC_REG_TIMER_CURRCNT 0x390 -#define LAPIC_REG_TIMER_DIV 0x3E0 -#define LAPIC_REG_ENABLE 0x80 -#define LAPIC_REG_SPURIOUS 0xF0 - -#define APIC_BASE_MSR 0x1B -#define APIC_BASE_MSR_BSP 0x100 -#define APIC_BASE_MSR_ENABLE 0x800 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////////////// - -/// @note: _hal_switch_context is internal. -/// @brief The **HAL** namespace. - -/////////////////////////////////////////////////////////////////////////////////////// - -namespace Kernel::HAL { -struct HAL_APIC_MADT; -struct HAL_HARDWARE_THREAD; - -struct HAL_HARDWARE_THREAD final { - StackFramePtr mFramePtr; - ProcessID mThreadID{0}; -}; - -EXTERN_C Void sched_jump_to_task(StackFramePtr stack_frame); - -STATIC HAL_APIC_MADT* kSMPBlock = nullptr; -STATIC Bool kSMPAware = false; -STATIC Int64 kSMPCount = 0; - -EXTERN_C UIntPtr kApicBaseAddress; - -STATIC Int32 kSMPInterrupt = 0; -STATIC UInt64 kAPICLocales[kMaxAPInsideSched] = {0}; -STATIC VoidPtr kRawMADT = nullptr; - -STATIC HAL_HARDWARE_THREAD kHWThread[kSchedProcessLimitPerTeam] = {{}}; - -/// @brief Multiple APIC Descriptor Table. -struct HAL_APIC_MADT final SDT_OBJECT { - UInt32 Address; // Madt address - UInt32 Flags; // Madt flags - UInt8 List[1]; // Records List -}; - -/// @brief Local APIC Descriptor Table. -struct LAPIC final { - UInt8 Type; - UInt8 Length; - UInt8 ProcessorID; - UInt8 APICID; - UInt32 Flags; -}; - -/////////////////////////////////////////////////////////////////////////////////////// - -/***********************************************************************************/ -/// @brief Send end IPI for CPU. -/// @param apic_id -/// @param vector -/// @param target -/// @return -/***********************************************************************************/ -EXTERN_C Void hal_send_ipi_msg(UInt32 target, UInt32 apic_id, UInt8 vector) { - Kernel::ke_dma_write(target, APIC_ICR_HIGH, apic_id << 24); - Kernel::ke_dma_write(target, APIC_ICR_LOW, 0x00000600 | 0x00004000 | 0x00000000 | vector); - - while (Kernel::ke_dma_read(target, APIC_ICR_LOW) & 0x1000) { - NE_UNUSED(0); - } -} - -/***********************************************************************************/ -/// @brief Get current stack frame for a thread. -/// @param thrdid The thread ID. -/***********************************************************************************/ - -EXTERN_C HAL::StackFramePtr mp_get_current_task(ThreadID thrdid) { - if (thrdid > kSMPCount) return nullptr; - return kHWThread[thrdid].mFramePtr; -} - -/***********************************************************************************/ -/// @brief Register current stack frame for a thread. -/// @param stack_frame The current stack frame. -/// @param thrdid The thread ID. -/***********************************************************************************/ - -EXTERN_C BOOL mp_register_task(HAL::StackFramePtr stack_frame, ThreadID thrdid) { - if (!stack_frame) return NO; - - if (!kSMPAware) { - sched_jump_to_task(stack_frame); - return YES; - } - - if (thrdid > kSMPCount) return NO; - - kHWThread[thrdid].mThreadID = thrdid; - kHWThread[thrdid].mFramePtr = stack_frame; - - hal_send_ipi_msg(thrdid, kAPICLocales[thrdid], kSMPInterrupt + 32); - - return YES; -} - -/***********************************************************************************/ -/// @brief Is the current config SMP aware? -/// @return True if YES, False if not. -/***********************************************************************************/ - -Bool mp_is_smp(Void) { - return kSMPAware; -} - -/***********************************************************************************/ -/// @brief Fetch and enable SMP scheduler. -/// @param vendor_ptr SMP containing structure. -/***********************************************************************************/ - -Void mp_init_cores(VoidPtr vendor_ptr) { - if (!vendor_ptr) return; - - PowerFactoryInterface hw_and_pow_int{vendor_ptr}; - - auto pwr = hw_and_pow_int.Find(APIC_MAG); - - if (pwr.HasError()) { - kSMPAware = NO; - return; - } - - kRawMADT = pwr.Leak().Leak(); - kSMPBlock = reinterpret_cast(kRawMADT); - kSMPAware = NO; - - if (kSMPBlock) { - kSMPInterrupt = 0; - kSMPCount = 0; - - UInt32 lo = 0U, hi = 0U; - - hal_get_msr(APIC_BASE_MSR, &lo, &hi); - - UInt64 apic_base = ((UInt64) hi << 32) | lo; - - apic_base |= APIC_BASE_MSR_ENABLE; // Enable APIC. - - lo = apic_base & 0xFFFFFFFF; - hi = apic_base >> 32; - - hal_set_msr(APIC_BASE_MSR, lo, hi); - - kApicBaseAddress = apic_base & 0xFFFFF000; - - LAPICDmaWrapper controller{(VoidPtr) kApicBaseAddress}; - - controller.Write(LAPIC_REG_ENABLE, 0); - controller.Write(LAPIC_REG_SPURIOUS, 0x1FF); // Enable bit, spurious interrupt vector register. - controller.Write(LAPIC_REG_TIMER_DIV, 0b0011); - controller.Write(LAPIC_REG_TIMER_LVT, 0x20 | (1 << 17)); - controller.Write(LAPIC_REG_TIMER_INITCNT, 1000000); - - volatile UInt8* entry_ptr = reinterpret_cast(kSMPBlock->List); - volatile UInt8* end_ptr = ((UInt8*) kSMPBlock) + kSMPBlock->Length; - - while (entry_ptr < end_ptr) { - UInt8 type = *entry_ptr; - UInt8 length = *(entry_ptr + 1); - - if (type == 0 && length == sizeof(struct LAPIC)) { - volatile LAPIC* entry_struct = (volatile LAPIC*) entry_ptr; - - if (entry_struct->Flags & 0x1) { - kAPICLocales[kSMPCount] = entry_struct->ProcessorID; - kHWThread[kSMPCount].mThreadID = kAPICLocales[kSMPCount]; - - ++kSMPCount; - - kout << "AP: kind: LAPIC: ON.\r"; - } else { - kout << "AP: kind: LAPIC: OFF.\r"; - } - } else { - kout << "AP: kind: UNKNOWN: OFF.\r"; - } - - entry_ptr += length; - } - } -} -} // namespace Kernel::HAL - -/////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/kernel/HALKit/AMD64/HalApplicationProcessor.cpp b/src/kernel/HALKit/AMD64/HalApplicationProcessor.cpp new file mode 100644 index 00000000..0450c71c --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalApplicationProcessor.cpp @@ -0,0 +1,218 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#define APIC_MAG "APIC" + +#define APIC_ICR_LOW 0x300 +#define APIC_ICR_HIGH 0x310 +#define APIC_SIPI_VEC 0x00500 +#define APIC_EIPI_VEC 0x00400 + +#define LAPIC_REG_TIMER_LVT 0x320 +#define LAPIC_REG_TIMER_INITCNT 0x380 +#define LAPIC_REG_TIMER_CURRCNT 0x390 +#define LAPIC_REG_TIMER_DIV 0x3E0 +#define LAPIC_REG_ENABLE 0x80 +#define LAPIC_REG_SPURIOUS 0xF0 + +#define APIC_BASE_MSR 0x1B +#define APIC_BASE_MSR_BSP 0x100 +#define APIC_BASE_MSR_ENABLE 0x800 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////////////// + +/// @note: _hal_switch_context is internal. +/// @brief The **HAL** namespace. + +/////////////////////////////////////////////////////////////////////////////////////// + +namespace Kernel::HAL { +struct HAL_APIC_MADT; +struct HAL_HARDWARE_THREAD; + +struct HAL_HARDWARE_THREAD final { + StackFramePtr mFramePtr; + ProcessID mThreadID{0}; +}; + +EXTERN_C Void sched_jump_to_task(StackFramePtr stack_frame); + +STATIC HAL_APIC_MADT* kSMPBlock = nullptr; +STATIC Bool kSMPAware = false; +STATIC Int64 kSMPCount = 0; + +EXTERN_C UIntPtr kApicBaseAddress; + +STATIC Int32 kSMPInterrupt = 0; +STATIC UInt64 kAPICLocales[kMaxAPInsideSched] = {0}; +STATIC VoidPtr kRawMADT = nullptr; + +STATIC HAL_HARDWARE_THREAD kHWThread[kSchedProcessLimitPerTeam] = {{}}; + +/// @brief Multiple APIC Descriptor Table. +struct HAL_APIC_MADT final SDT_OBJECT { + UInt32 Address; // Madt address + UInt32 Flags; // Madt flags + UInt8 List[1]; // Records List +}; + +/// @brief Local APIC Descriptor Table. +struct LAPIC final { + UInt8 Type; + UInt8 Length; + UInt8 ProcessorID; + UInt8 APICID; + UInt32 Flags; +}; + +/////////////////////////////////////////////////////////////////////////////////////// + +/***********************************************************************************/ +/// @brief Send end IPI for CPU. +/// @param apic_id +/// @param vector +/// @param target +/// @return +/***********************************************************************************/ +EXTERN_C Void hal_send_ipi_msg(UInt32 target, UInt32 apic_id, UInt8 vector) { + Kernel::ke_dma_write(target, APIC_ICR_HIGH, apic_id << 24); + Kernel::ke_dma_write(target, APIC_ICR_LOW, 0x00000600 | 0x00004000 | 0x00000000 | vector); + + while (Kernel::ke_dma_read(target, APIC_ICR_LOW) & 0x1000) { + NE_UNUSED(0); + } +} + +/***********************************************************************************/ +/// @brief Get current stack frame for a thread. +/// @param thrdid The thread ID. +/***********************************************************************************/ + +EXTERN_C HAL::StackFramePtr mp_get_current_task(ThreadID thrdid) { + if (thrdid > kSMPCount) return nullptr; + return kHWThread[thrdid].mFramePtr; +} + +/***********************************************************************************/ +/// @brief Register current stack frame for a thread. +/// @param stack_frame The current stack frame. +/// @param thrdid The thread ID. +/***********************************************************************************/ + +EXTERN_C BOOL mp_register_task(HAL::StackFramePtr stack_frame, ThreadID thrdid) { + if (!stack_frame) return NO; + + if (!kSMPAware) { + sched_jump_to_task(stack_frame); + return YES; + } + + if (thrdid > kSMPCount) return NO; + + kHWThread[thrdid].mThreadID = thrdid; + kHWThread[thrdid].mFramePtr = stack_frame; + + hal_send_ipi_msg(thrdid, kAPICLocales[thrdid], kSMPInterrupt + 32); + + return YES; +} + +/***********************************************************************************/ +/// @brief Is the current config SMP aware? +/// @return True if YES, False if not. +/***********************************************************************************/ + +Bool mp_is_smp(Void) { + return kSMPAware; +} + +/***********************************************************************************/ +/// @brief Fetch and enable SMP scheduler. +/// @param vendor_ptr SMP containing structure. +/***********************************************************************************/ + +Void mp_init_cores(VoidPtr vendor_ptr) { + if (!vendor_ptr) return; + + PowerFactoryInterface hw_and_pow_int{vendor_ptr}; + + auto pwr = hw_and_pow_int.Find(APIC_MAG); + + if (pwr.HasError()) { + kSMPAware = NO; + return; + } + + kRawMADT = pwr.Leak().Leak(); + kSMPBlock = reinterpret_cast(kRawMADT); + kSMPAware = NO; + + if (kSMPBlock) { + kSMPInterrupt = 0; + kSMPCount = 0; + + UInt32 lo = 0U, hi = 0U; + + hal_get_msr(APIC_BASE_MSR, &lo, &hi); + + UInt64 apic_base = ((UInt64) hi << 32) | lo; + + apic_base |= APIC_BASE_MSR_ENABLE; // Enable APIC. + + lo = apic_base & 0xFFFFFFFF; + hi = apic_base >> 32; + + hal_set_msr(APIC_BASE_MSR, lo, hi); + + kApicBaseAddress = apic_base & 0xFFFFF000; + + LAPICDmaWrapper controller{(VoidPtr) kApicBaseAddress}; + + controller.Write(LAPIC_REG_ENABLE, 0); + controller.Write(LAPIC_REG_SPURIOUS, 0x1FF); // Enable bit, spurious interrupt vector register. + controller.Write(LAPIC_REG_TIMER_DIV, 0b0011); + controller.Write(LAPIC_REG_TIMER_LVT, 0x20 | (1 << 17)); + controller.Write(LAPIC_REG_TIMER_INITCNT, 1000000); + + volatile UInt8* entry_ptr = reinterpret_cast(kSMPBlock->List); + volatile UInt8* end_ptr = ((UInt8*) kSMPBlock) + kSMPBlock->Length; + + while (entry_ptr < end_ptr) { + UInt8 type = *entry_ptr; + UInt8 length = *(entry_ptr + 1); + + if (type == 0 && length == sizeof(struct LAPIC)) { + volatile LAPIC* entry_struct = (volatile LAPIC*) entry_ptr; + + if (entry_struct->Flags & 0x1) { + kAPICLocales[kSMPCount] = entry_struct->ProcessorID; + kHWThread[kSMPCount].mThreadID = kAPICLocales[kSMPCount]; + + ++kSMPCount; + + kout << "AP: kind: LAPIC: ON.\r"; + } else { + kout << "AP: kind: LAPIC: OFF.\r"; + } + } else { + kout << "AP: kind: UNKNOWN: OFF.\r"; + } + + entry_ptr += length; + } + } +} +} // namespace Kernel::HAL + +/////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc b/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc deleted file mode 100644 index a171ac57..00000000 --- a/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include - -EXTERN_C Kernel::Void idt_handle_breakpoint(Kernel::UIntPtr rip); -EXTERN_C Kernel::UIntPtr kApicBaseAddress; - -STATIC BOOL kIsRunning{NO}; - -/// @brief Notify APIC and PIC that we're done with the interrupt. -/// @note -static void hal_idt_send_eoi(UInt8 vector) { - ((volatile UInt32*) kApicBaseAddress)[0xB0 / 4] = 0; - - if (vector >= kPICCommand && vector <= 0x2F) { - if (vector >= 0x28) { - Kernel::HAL::rt_out8(kPIC2Command, kPICCommand); - } - Kernel::HAL::rt_out8(kPICCommand, kPICCommand); - } -} - -/// @brief Handle GPF fault. -/// @param rsp -EXTERN_C Kernel::Void idt_handle_gpf(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - if (process) process.Crash(); - - hal_idt_send_eoi(13); - - if (process) { - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; - } -} - -/// @brief Handle page fault. -/// @param rsp -EXTERN_C void idt_handle_pf(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - if (process) process.Crash(); - - hal_idt_send_eoi(14); - - if (process) { - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; - } -} - -/// @brief Handle scheduler interrupt. -EXTERN_C void idt_handle_scheduler(Kernel::UIntPtr rsp) { - NE_UNUSED(rsp); - - hal_idt_send_eoi(32); - - while (kIsRunning); - - kIsRunning = YES; - - Kernel::UserProcessHelper::StartScheduling(); - - kIsRunning = NO; -} - -/// @brief Handle math fault. -/// @param rsp -EXTERN_C void idt_handle_math(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - if (process) process.Crash(); - - hal_idt_send_eoi(8); - - if (process) { - process.Signal.SignalArg = rsp; - process.Signal.SignalID = sig_generate_unique(); - process.Signal.Status = process.Status; - } -} - -/// @brief Handle any generic fault. -/// @param rsp -EXTERN_C void idt_handle_generic(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - if (process) process.Crash(); - - hal_idt_send_eoi(30); - - Kernel::kout << "Kernel: Generic Process Fault.\r"; - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = sig_generate_unique(); - ; - process.Signal.Status = process.Status; - - Kernel::kout << "Kernel: SIGKILL status.\r"; -} - -EXTERN_C Kernel::Void idt_handle_breakpoint(Kernel::UIntPtr rip) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - if (process) process.Crash(); - - hal_idt_send_eoi(3); - - process.Signal.SignalArg = rip; - process.Signal.SignalID = sig_generate_unique(); - - process.Signal.Status = process.Status; - - process.Status = Kernel::ProcessStatusKind::kFrozen; -} - -/// @brief Handle #UD fault. -/// @param rsp -EXTERN_C void idt_handle_ud(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - if (process) process.Crash(); - - hal_idt_send_eoi(6); - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = sig_generate_unique(); - process.Signal.Status = process.Status; -} - -/// @brief Enter syscall from assembly (libSystem only) -/// @param stack the stack pushed from assembly routine. -/// @return nothing. -EXTERN_C Kernel::Void hal_system_call_enter(Kernel::UIntPtr rcx_hash, - Kernel::UIntPtr rdx_syscall_arg) { - hal_idt_send_eoi(50); - - if (!Kernel::kCurrentUser) return; - - for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { - if (kSysCalls[i].fHooked && rcx_hash == kSysCalls[i].fHash) { - if (kSysCalls[i].fProc) { - (kSysCalls[i].fProc)((Kernel::VoidPtr) rdx_syscall_arg); - } - } - } -} - -/// @brief Enter Kernel call from assembly (libDDK only). -/// @param stack the stack pushed from assembly routine. -/// @return nothing. -EXTERN_C Kernel::Void hal_kernel_call_enter(Kernel::UIntPtr rcx_hash, Kernel::SizeT cnt, - Kernel::UIntPtr arg, Kernel::SizeT sz) { - hal_idt_send_eoi(51); - - if (!Kernel::kRootUser) return; - if (Kernel::kCurrentUser != Kernel::kRootUser) return; - if (!Kernel::kCurrentUser->IsSuperUser()) return; - - for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { - if (kKernCalls[i].fHooked && rcx_hash == kKernCalls[rcx_hash].fHash) { - if (kKernCalls[i].fProc) { - (kKernCalls[i].fProc)(cnt, (Kernel::VoidPtr) arg, sz); - } - } - } -} diff --git a/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cpp b/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cpp new file mode 100644 index 00000000..a171ac57 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cpp @@ -0,0 +1,177 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include + +EXTERN_C Kernel::Void idt_handle_breakpoint(Kernel::UIntPtr rip); +EXTERN_C Kernel::UIntPtr kApicBaseAddress; + +STATIC BOOL kIsRunning{NO}; + +/// @brief Notify APIC and PIC that we're done with the interrupt. +/// @note +static void hal_idt_send_eoi(UInt8 vector) { + ((volatile UInt32*) kApicBaseAddress)[0xB0 / 4] = 0; + + if (vector >= kPICCommand && vector <= 0x2F) { + if (vector >= 0x28) { + Kernel::HAL::rt_out8(kPIC2Command, kPICCommand); + } + Kernel::HAL::rt_out8(kPICCommand, kPICCommand); + } +} + +/// @brief Handle GPF fault. +/// @param rsp +EXTERN_C Kernel::Void idt_handle_gpf(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + if (process) process.Crash(); + + hal_idt_send_eoi(13); + + if (process) { + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; + } +} + +/// @brief Handle page fault. +/// @param rsp +EXTERN_C void idt_handle_pf(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + if (process) process.Crash(); + + hal_idt_send_eoi(14); + + if (process) { + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; + } +} + +/// @brief Handle scheduler interrupt. +EXTERN_C void idt_handle_scheduler(Kernel::UIntPtr rsp) { + NE_UNUSED(rsp); + + hal_idt_send_eoi(32); + + while (kIsRunning); + + kIsRunning = YES; + + Kernel::UserProcessHelper::StartScheduling(); + + kIsRunning = NO; +} + +/// @brief Handle math fault. +/// @param rsp +EXTERN_C void idt_handle_math(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + if (process) process.Crash(); + + hal_idt_send_eoi(8); + + if (process) { + process.Signal.SignalArg = rsp; + process.Signal.SignalID = sig_generate_unique(); + process.Signal.Status = process.Status; + } +} + +/// @brief Handle any generic fault. +/// @param rsp +EXTERN_C void idt_handle_generic(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + if (process) process.Crash(); + + hal_idt_send_eoi(30); + + Kernel::kout << "Kernel: Generic Process Fault.\r"; + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = sig_generate_unique(); + ; + process.Signal.Status = process.Status; + + Kernel::kout << "Kernel: SIGKILL status.\r"; +} + +EXTERN_C Kernel::Void idt_handle_breakpoint(Kernel::UIntPtr rip) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + if (process) process.Crash(); + + hal_idt_send_eoi(3); + + process.Signal.SignalArg = rip; + process.Signal.SignalID = sig_generate_unique(); + + process.Signal.Status = process.Status; + + process.Status = Kernel::ProcessStatusKind::kFrozen; +} + +/// @brief Handle #UD fault. +/// @param rsp +EXTERN_C void idt_handle_ud(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + if (process) process.Crash(); + + hal_idt_send_eoi(6); + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = sig_generate_unique(); + process.Signal.Status = process.Status; +} + +/// @brief Enter syscall from assembly (libSystem only) +/// @param stack the stack pushed from assembly routine. +/// @return nothing. +EXTERN_C Kernel::Void hal_system_call_enter(Kernel::UIntPtr rcx_hash, + Kernel::UIntPtr rdx_syscall_arg) { + hal_idt_send_eoi(50); + + if (!Kernel::kCurrentUser) return; + + for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { + if (kSysCalls[i].fHooked && rcx_hash == kSysCalls[i].fHash) { + if (kSysCalls[i].fProc) { + (kSysCalls[i].fProc)((Kernel::VoidPtr) rdx_syscall_arg); + } + } + } +} + +/// @brief Enter Kernel call from assembly (libDDK only). +/// @param stack the stack pushed from assembly routine. +/// @return nothing. +EXTERN_C Kernel::Void hal_kernel_call_enter(Kernel::UIntPtr rcx_hash, Kernel::SizeT cnt, + Kernel::UIntPtr arg, Kernel::SizeT sz) { + hal_idt_send_eoi(51); + + if (!Kernel::kRootUser) return; + if (Kernel::kCurrentUser != Kernel::kRootUser) return; + if (!Kernel::kCurrentUser->IsSuperUser()) return; + + for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { + if (kKernCalls[i].fHooked && rcx_hash == kKernCalls[rcx_hash].fHash) { + if (kKernCalls[i].fProc) { + (kKernCalls[i].fProc)(cnt, (Kernel::VoidPtr) arg, sz); + } + } + } +} diff --git a/src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cc b/src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cc deleted file mode 100644 index 7322ae93..00000000 --- a/src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cc +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2026, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -namespace Kernel {} \ No newline at end of file diff --git a/src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cpp b/src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cpp new file mode 100644 index 00000000..7322ae93 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalCoreSystemCalls+DDK.cpp @@ -0,0 +1,7 @@ +// Copyright 2026, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +namespace Kernel {} \ No newline at end of file diff --git a/src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cc b/src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cc deleted file mode 100644 index 33d1243a..00000000 --- a/src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cc +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2026, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -namespace Kernel {} diff --git a/src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cpp b/src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cpp new file mode 100644 index 00000000..33d1243a --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalCoreSystemCalls+NeLaunch.cpp @@ -0,0 +1,7 @@ +// Copyright 2026, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +namespace Kernel {} diff --git a/src/kernel/HALKit/AMD64/HalDebugOutput.cc b/src/kernel/HALKit/AMD64/HalDebugOutput.cc deleted file mode 100644 index dbddd092..00000000 --- a/src/kernel/HALKit/AMD64/HalDebugOutput.cc +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include - -namespace Kernel { -enum CommStatus : UInt16 { - kStateInvalid = 0x64, - kStateReady = 0xCF, - kStateTransmit = 0xFC, - kStateCnt = 3 -}; - -namespace Detail { - constexpr ATTRIBUTE(unused) const UInt16 kPort = 0x3F8; - STATIC ATTRIBUTE(unused) UInt16 kState = kStateInvalid; - - /// @brief Init COM1. - /// @return - template - bool hal_serial_init() { - if (kState == kStateReady || kState == kStateTransmit) return true; - - HAL::rt_out8(PORT + 1, 0x00); // Disable all interrupts - HAL::rt_out8(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) - HAL::rt_out8(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud - HAL::rt_out8(PORT + 1, 0x00); // (hi byte) - HAL::rt_out8(PORT + 3, 0x03); // 8 bits, no parity, one stop bit - HAL::rt_out8(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold - HAL::rt_out8(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - HAL::rt_out8(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip - HAL::rt_out8(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if - // serial returns same byte) - - // Check if serial is faulty (i.e: not same byte as sent) - if (HAL::rt_in8(PORT) != 0xAE) { - return false; - } - - kState = kStateReady; - - // If serial is not faulty set it in normal operation mode - // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - HAL::rt_out8(PORT + 4, 0x0F); - - return true; - } -} // namespace Detail - -TerminalDevice::~TerminalDevice() = default; - -#ifdef __DEBUG__ -STATIC SizeT kX = kFontSizeX, kY = kFontSizeY; -#endif // __DEBUG__ - -EXTERN_C void ke_utf_io_write(IDevice* obj, const Utf8Char* bytes) { - NE_UNUSED(bytes); - NE_UNUSED(obj); - -#ifdef __DEBUG__ - Detail::hal_serial_init(); - - if (!bytes || Detail::kState != kStateReady) return; - - if (*bytes == 0) return; - - Detail::kState = kStateTransmit; - - SizeT index = 0; - SizeT len = 0; - - index = 0; - len = urt_string_len(bytes); - - Char tmp_str[2]; - - while (index < len) { - if (bytes[index] == '\r') HAL::rt_out8(Detail::kPort, '\r'); - - HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); - - tmp_str[0] = (bytes[index] > 127) ? '?' : bytes[index]; - tmp_str[1] = 0; - - cg_render_string(tmp_str, kY, kX, RGB(0xff, 0xff, 0xff)); - - if (bytes[index] == '\r') { - kY += kFontSizeY; - kX = kFontSizeX; - } - - kX += kFontSizeX; - - if (kX > kHandoverHeader->f_GOP.f_Width) { - kX = kFontSizeX; - } - - if (kY > kHandoverHeader->f_GOP.f_Height) { - kY = kFontSizeY; - - FBDrawInRegion(cg_get_clear_clr(), FB::CGAccessibilty::Height(), FB::CGAccessibilty::Width(), - 0, 0); - } - - ++index; - } - - Detail::kState = kStateReady; -#endif // __DEBUG__ -} - -EXTERN_C void ke_io_write(IDevice* obj, const Char* bytes) { - NE_UNUSED(bytes); - NE_UNUSED(obj); - -#ifdef __DEBUG__ - Detail::hal_serial_init(); - - if (!bytes || Detail::kState != kStateReady) return; - - if (*bytes == 0) return; - - Detail::kState = kStateTransmit; - - SizeT index = 0; - SizeT len = 0; - - index = 0; - len = rt_string_len(bytes); - - Char tmp_str[2]; - - while (index < len) { - if (bytes[index] == '\r') HAL::rt_out8(Detail::kPort, '\r'); - - HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); - - tmp_str[0] = bytes[index]; - tmp_str[1] = 0; - - cg_render_string(tmp_str, kY, kX, RGB(0xff, 0xff, 0xff)); - - if (bytes[index] == '\r') { - kY += kFontSizeY; - kX = kFontSizeX; - } - - kX += kFontSizeX; - - if (kX > kHandoverHeader->f_GOP.f_Width) { - kX = kFontSizeX; - } - - if (kY > kHandoverHeader->f_GOP.f_Height) { - kY = kFontSizeY; - - FBDrawInRegion(cg_get_clear_clr(), FB::CGAccessibilty::Height(), FB::CGAccessibilty::Width(), - 0, 0); - } - - ++index; - } - - Detail::kState = kStateReady; -#endif // __DEBUG__ -} - -EXTERN_C void ke_io_read(IDevice*, const Char* bytes) { - NE_UNUSED(bytes); - -#ifdef __DEBUG__ - Detail::hal_serial_init(); - - if (!bytes || Detail::kState != kStateReady) return; - - Detail::kState = kStateTransmit; - - SizeT index = 0; - - ///! TODO: Look on how to wait for the UART to complete. - while (true) { - auto in = HAL::rt_in8(Detail::kPort); - - ///! If enter pressed then break. - if (in == 0xD) { - break; - } - - if (in < '0' || in < 'A' || in < 'a') { - if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || in != ':') { - continue; - } - } - - ((char*) bytes)[index] = in; - - ++index; - } - - ((char*) bytes)[index] = 0; - - Detail::kState = kStateReady; -#endif // __DEBUG__ -} - -TerminalDevice TerminalDevice::The() { - TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read); - return out; -} - -Utf8TerminalDevice::~Utf8TerminalDevice() = default; - -Utf8TerminalDevice Utf8TerminalDevice::The() { - Utf8TerminalDevice out(Kernel::ke_utf_io_write, - [](IDevice*, const Utf8Char*) -> Void {}); - return out; -} - -} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalDebugOutput.cpp b/src/kernel/HALKit/AMD64/HalDebugOutput.cpp new file mode 100644 index 00000000..dbddd092 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalDebugOutput.cpp @@ -0,0 +1,225 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include + +namespace Kernel { +enum CommStatus : UInt16 { + kStateInvalid = 0x64, + kStateReady = 0xCF, + kStateTransmit = 0xFC, + kStateCnt = 3 +}; + +namespace Detail { + constexpr ATTRIBUTE(unused) const UInt16 kPort = 0x3F8; + STATIC ATTRIBUTE(unused) UInt16 kState = kStateInvalid; + + /// @brief Init COM1. + /// @return + template + bool hal_serial_init() { + if (kState == kStateReady || kState == kStateTransmit) return true; + + HAL::rt_out8(PORT + 1, 0x00); // Disable all interrupts + HAL::rt_out8(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + HAL::rt_out8(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + HAL::rt_out8(PORT + 1, 0x00); // (hi byte) + HAL::rt_out8(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + HAL::rt_out8(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + HAL::rt_out8(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + HAL::rt_out8(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + HAL::rt_out8(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if + // serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if (HAL::rt_in8(PORT) != 0xAE) { + return false; + } + + kState = kStateReady; + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + HAL::rt_out8(PORT + 4, 0x0F); + + return true; + } +} // namespace Detail + +TerminalDevice::~TerminalDevice() = default; + +#ifdef __DEBUG__ +STATIC SizeT kX = kFontSizeX, kY = kFontSizeY; +#endif // __DEBUG__ + +EXTERN_C void ke_utf_io_write(IDevice* obj, const Utf8Char* bytes) { + NE_UNUSED(bytes); + NE_UNUSED(obj); + +#ifdef __DEBUG__ + Detail::hal_serial_init(); + + if (!bytes || Detail::kState != kStateReady) return; + + if (*bytes == 0) return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = urt_string_len(bytes); + + Char tmp_str[2]; + + while (index < len) { + if (bytes[index] == '\r') HAL::rt_out8(Detail::kPort, '\r'); + + HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); + + tmp_str[0] = (bytes[index] > 127) ? '?' : bytes[index]; + tmp_str[1] = 0; + + cg_render_string(tmp_str, kY, kX, RGB(0xff, 0xff, 0xff)); + + if (bytes[index] == '\r') { + kY += kFontSizeY; + kX = kFontSizeX; + } + + kX += kFontSizeX; + + if (kX > kHandoverHeader->f_GOP.f_Width) { + kX = kFontSizeX; + } + + if (kY > kHandoverHeader->f_GOP.f_Height) { + kY = kFontSizeY; + + FBDrawInRegion(cg_get_clear_clr(), FB::CGAccessibilty::Height(), FB::CGAccessibilty::Width(), + 0, 0); + } + + ++index; + } + + Detail::kState = kStateReady; +#endif // __DEBUG__ +} + +EXTERN_C void ke_io_write(IDevice* obj, const Char* bytes) { + NE_UNUSED(bytes); + NE_UNUSED(obj); + +#ifdef __DEBUG__ + Detail::hal_serial_init(); + + if (!bytes || Detail::kState != kStateReady) return; + + if (*bytes == 0) return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = rt_string_len(bytes); + + Char tmp_str[2]; + + while (index < len) { + if (bytes[index] == '\r') HAL::rt_out8(Detail::kPort, '\r'); + + HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); + + tmp_str[0] = bytes[index]; + tmp_str[1] = 0; + + cg_render_string(tmp_str, kY, kX, RGB(0xff, 0xff, 0xff)); + + if (bytes[index] == '\r') { + kY += kFontSizeY; + kX = kFontSizeX; + } + + kX += kFontSizeX; + + if (kX > kHandoverHeader->f_GOP.f_Width) { + kX = kFontSizeX; + } + + if (kY > kHandoverHeader->f_GOP.f_Height) { + kY = kFontSizeY; + + FBDrawInRegion(cg_get_clear_clr(), FB::CGAccessibilty::Height(), FB::CGAccessibilty::Width(), + 0, 0); + } + + ++index; + } + + Detail::kState = kStateReady; +#endif // __DEBUG__ +} + +EXTERN_C void ke_io_read(IDevice*, const Char* bytes) { + NE_UNUSED(bytes); + +#ifdef __DEBUG__ + Detail::hal_serial_init(); + + if (!bytes || Detail::kState != kStateReady) return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + + ///! TODO: Look on how to wait for the UART to complete. + while (true) { + auto in = HAL::rt_in8(Detail::kPort); + + ///! If enter pressed then break. + if (in == 0xD) { + break; + } + + if (in < '0' || in < 'A' || in < 'a') { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || in != ':') { + continue; + } + } + + ((char*) bytes)[index] = in; + + ++index; + } + + ((char*) bytes)[index] = 0; + + Detail::kState = kStateReady; +#endif // __DEBUG__ +} + +TerminalDevice TerminalDevice::The() { + TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read); + return out; +} + +Utf8TerminalDevice::~Utf8TerminalDevice() = default; + +Utf8TerminalDevice Utf8TerminalDevice::The() { + Utf8TerminalDevice out(Kernel::ke_utf_io_write, + [](IDevice*, const Utf8Char*) -> Void {}); + return out; +} + +} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalDebugProtocol.cc b/src/kernel/HALKit/AMD64/HalDebugProtocol.cc deleted file mode 100644 index e7a2881b..00000000 --- a/src/kernel/HALKit/AMD64/HalDebugProtocol.cc +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -// after that we have start of additional data. - -namespace Kernel {} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalDebugProtocol.cpp b/src/kernel/HALKit/AMD64/HalDebugProtocol.cpp new file mode 100644 index 00000000..e7a2881b --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalDebugProtocol.cpp @@ -0,0 +1,11 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +// after that we have start of additional data. + +namespace Kernel {} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalDescriptorLoader.cc b/src/kernel/HALKit/AMD64/HalDescriptorLoader.cc deleted file mode 100644 index e803f7a8..00000000 --- a/src/kernel/HALKit/AMD64/HalDescriptorLoader.cc +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -namespace Kernel::HAL { -namespace Detail { - STATIC ::Kernel::Detail::AMD64::InterruptDescriptorAMD64 kInterruptVectorTable[kKernelIdtSize] = - {}; -} // namespace Detail - -/// @brief Loads the provided Global Descriptor Table. -/// @param gdt -/// @return -Void GDTLoader::Load(Register64& gdt) { -#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ - hal_load_gdt(gdt); -#endif // __NE_MODULAR_KERNEL_COMPONENTS__ -} - -Void IDTLoader::Load(Register64& idt) { -#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ - rt_cli(); - - volatile UIntPtr** ptr_ivt = (volatile UIntPtr**) idt.Base; - - for (SizeT idt_indx = 0; idt_indx < kKernelIdtSize; ++idt_indx) { - Detail::kInterruptVectorTable[idt_indx].Selector = kIDTSelector; - Detail::kInterruptVectorTable[idt_indx].Ist = 0; - Detail::kInterruptVectorTable[idt_indx].TypeAttributes = - kKernelInterruptId ? kUserInterruptGate : kInterruptGate; - Detail::kInterruptVectorTable[idt_indx].OffsetLow = ((UIntPtr) ptr_ivt[idt_indx] & 0xFFFF); - Detail::kInterruptVectorTable[idt_indx].OffsetMid = - (((UIntPtr) ptr_ivt[idt_indx] >> 16) & 0xFFFF); - Detail::kInterruptVectorTable[idt_indx].OffsetHigh = - (((UIntPtr) ptr_ivt[idt_indx] >> 32) & 0xFFFFFFFF); - - Detail::kInterruptVectorTable[idt_indx].Zero = 0; - } - - idt.Base = (UIntPtr) &Detail::kInterruptVectorTable[0]; - idt.Limit = sizeof(::Kernel::Detail::AMD64::InterruptDescriptorAMD64) * (kKernelIdtSize); - - hal_load_idt(idt); - rt_sti(); -#endif // __NE_MODULAR_KERNEL_COMPONENTS__ - - return; -} - -/// @brief Loads the Global Descriptor Table into the CPU. -/// @param gdt GDT register wrapped in a ref. -void GDTLoader::Load(Ref& gdt) { - if (!gdt) return; - - GDTLoader::Load(gdt.Leak()); -} - -/// @brief Loads the IDT, for interupts. -/// @param idt IDT register wrapped in a ref. -void IDTLoader::Load(Ref& idt) { - if (!idt) return; - - IDTLoader::Load(idt.Leak()); -} -} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalDescriptorLoader.cpp b/src/kernel/HALKit/AMD64/HalDescriptorLoader.cpp new file mode 100644 index 00000000..e803f7a8 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalDescriptorLoader.cpp @@ -0,0 +1,69 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +namespace Kernel::HAL { +namespace Detail { + STATIC ::Kernel::Detail::AMD64::InterruptDescriptorAMD64 kInterruptVectorTable[kKernelIdtSize] = + {}; +} // namespace Detail + +/// @brief Loads the provided Global Descriptor Table. +/// @param gdt +/// @return +Void GDTLoader::Load(Register64& gdt) { +#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ + hal_load_gdt(gdt); +#endif // __NE_MODULAR_KERNEL_COMPONENTS__ +} + +Void IDTLoader::Load(Register64& idt) { +#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ + rt_cli(); + + volatile UIntPtr** ptr_ivt = (volatile UIntPtr**) idt.Base; + + for (SizeT idt_indx = 0; idt_indx < kKernelIdtSize; ++idt_indx) { + Detail::kInterruptVectorTable[idt_indx].Selector = kIDTSelector; + Detail::kInterruptVectorTable[idt_indx].Ist = 0; + Detail::kInterruptVectorTable[idt_indx].TypeAttributes = + kKernelInterruptId ? kUserInterruptGate : kInterruptGate; + Detail::kInterruptVectorTable[idt_indx].OffsetLow = ((UIntPtr) ptr_ivt[idt_indx] & 0xFFFF); + Detail::kInterruptVectorTable[idt_indx].OffsetMid = + (((UIntPtr) ptr_ivt[idt_indx] >> 16) & 0xFFFF); + Detail::kInterruptVectorTable[idt_indx].OffsetHigh = + (((UIntPtr) ptr_ivt[idt_indx] >> 32) & 0xFFFFFFFF); + + Detail::kInterruptVectorTable[idt_indx].Zero = 0; + } + + idt.Base = (UIntPtr) &Detail::kInterruptVectorTable[0]; + idt.Limit = sizeof(::Kernel::Detail::AMD64::InterruptDescriptorAMD64) * (kKernelIdtSize); + + hal_load_idt(idt); + rt_sti(); +#endif // __NE_MODULAR_KERNEL_COMPONENTS__ + + return; +} + +/// @brief Loads the Global Descriptor Table into the CPU. +/// @param gdt GDT register wrapped in a ref. +void GDTLoader::Load(Ref& gdt) { + if (!gdt) return; + + GDTLoader::Load(gdt.Leak()); +} + +/// @brief Loads the IDT, for interupts. +/// @param idt IDT register wrapped in a ref. +void IDTLoader::Load(Ref& idt) { + if (!idt) return; + + IDTLoader::Load(idt.Leak()); +} +} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalKernelMain.cc b/src/kernel/HALKit/AMD64/HalKernelMain.cc deleted file mode 100644 index 7e6579de..00000000 --- a/src/kernel/HALKit/AMD64/HalKernelMain.cc +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ -EXTERN_C Kernel::VoidPtr kInterruptVectorTable[]; - -/// @brief Kernel init function. -/// @param handover_hdr Handover boot header. -EXTERN_C Kernel::Int32 hal_init_platform(Kernel::HEL::BootInfoHeader* handover_hdr) { - using namespace Kernel; - - if (handover_hdr->f_Magic != kHandoverMagic && handover_hdr->f_Version != kHandoverVersion) { - return kEfiFail; - } - - HAL::rt_sti(); - - fw_init_efi((EfiSystemTable*) handover_hdr->f_FirmwareCustomTables[1]); - - Boot::ExitBootServices(handover_hdr->f_HardwareTables.f_ImageKey, - handover_hdr->f_HardwareTables.f_ImageHandle); - - kHandoverHeader = handover_hdr; - - kKernelVM = kHandoverHeader->f_PageStart; - - if (!kKernelVM) { - MUST_PASS(kKernelVM); - return kEfiFail; - } - - hal_write_cr3(kKernelVM); - - /************************************** */ - /* INITIALIZE BIT MAP. */ - /************************************** */ - - kBitMapCursor = 0UL; - kKernelBitMpSize = kHandoverHeader->f_BitMapSize; - kKernelBitMpStart = - reinterpret_cast(reinterpret_cast(kHandoverHeader->f_BitMapStart)); - - /************************************** */ - /* INITIALIZE GDT AND SEGMENTS. */ - /************************************** */ - - STATIC CONST auto kGDTEntriesCount = 8; - - STATIC HAL::Detail::NE_TSS kKernelTSS{}; - - kKernelTSS.fRsp0 = (UInt64) kHandoverHeader->f_StackTop; - kKernelTSS.fIopb = sizeof(HAL::Detail::NE_TSS); - - /* The GDT, mostly descriptors for user and kernel segments. */ - STATIC HAL::Detail::NE_GDT_ENTRY ALIGN(0x08) kGDTArray[kGDTEntriesCount] = { - {.fLimitLow = 0, - .fBaseLow = 0, - .fBaseMid = 0, - .fAccessByte = 0x00, - .fFlags = 0x00, - .fBaseHigh = 0}, // Null entry - {.fLimitLow = 0x0, - .fBaseLow = 0, - .fBaseMid = 0, - .fAccessByte = 0x9A, - .fFlags = 0xAF, - .fBaseHigh = 0}, // Kernel code - {.fLimitLow = 0x0, - .fBaseLow = 0, - .fBaseMid = 0, - .fAccessByte = 0x92, - .fFlags = 0xCF, - .fBaseHigh = 0}, // Kernel data - {}, // TSS data low - {}, // TSS data high - {.fLimitLow = 0x0, - .fBaseLow = 0, - .fBaseMid = 0, - .fAccessByte = 0xFA, - .fFlags = 0xAF, - .fBaseHigh = 0}, // User code - {.fLimitLow = 0x0, - .fBaseLow = 0, - .fBaseMid = 0, - .fAccessByte = 0xF2, - .fFlags = 0xCF, - .fBaseHigh = 0}, // User data - }; - - kGDTArray[3].fLimitLow = sizeof(HAL::Detail::NE_TSS) - 1; - kGDTArray[3].fBaseLow = ((UIntPtr) &kKernelTSS) & 0xFFFF; - kGDTArray[3].fBaseMid = (((UIntPtr) &kKernelTSS) >> 16) & 0xFF; - kGDTArray[3].fAccessByte = 0x89; // Present, type 9 = 64-bit available TSS - kGDTArray[3].fFlags = 0x20 | ((((UIntPtr) &kKernelTSS) >> 24) & 0x0F); - kGDTArray[3].fBaseHigh = (((UIntPtr) &kKernelTSS) >> 24) & 0xFF; - - kGDTArray[4].fLimitLow = ((UIntPtr) &kKernelTSS >> 32) & 0xFFFF; - kGDTArray[4].fBaseLow = 0; - kGDTArray[4].fBaseMid = 0; - kGDTArray[4].fAccessByte = 0; - kGDTArray[4].fFlags = 0; - kGDTArray[4].fBaseHigh = 0; - - FB::cg_clear_video(); - - // Load memory descriptors. - HAL::Register64 gdt_reg; - - gdt_reg.Base = reinterpret_cast(kGDTArray); - gdt_reg.Limit = (sizeof(HAL::Detail::NE_GDT_ENTRY) * kGDTEntriesCount) - 1; - - //! GDT will load hal_read_init after it successfully loads the segments. - HAL::GDTLoader gdt_loader; - gdt_loader.Load(gdt_reg); - - return kEfiFail; -} - -EXTERN_C Kernel::Void hal_real_init(Kernel::Void) { - HAL::mp_init_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr); - - HAL::Register64 idt_reg; - idt_reg.Base = reinterpret_cast(kInterruptVectorTable); - - HAL::IDTLoader idt_loader; - idt_loader.Load(idt_reg); - -#ifdef __FSKIT_INCLUDES_OPENHEFS__ - OpenHeFS::fs_init_openhefs(); - HeFileSystemMgr::Mount(new HeFileSystemMgr()); -#endif - -#ifdef __FSKIT_INCLUDES_NEFS__ - NeFS::fs_init_nefs(); - NeFileSystemMgr::Mount(new NeFileSystemMgr()); -#endif - - UserProcessScheduler::The().SwitchTeam(kRTUserTeam); - - PEFLoader ldr("/system/init.out"); - - if (ldr.IsLoaded()) rtl_create_user_process(ldr, UserProcess::ExecutableKind::kExecutableKind); - - UserProcessScheduler::The().SwitchTeam(kMidUserTeam); - - while (YES); -} -#endif // ifndef __NE_MODULAR_KERNEL_COMPONENTS__ diff --git a/src/kernel/HALKit/AMD64/HalKernelMain.cpp b/src/kernel/HALKit/AMD64/HalKernelMain.cpp new file mode 100644 index 00000000..7e6579de --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalKernelMain.cpp @@ -0,0 +1,164 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ +EXTERN_C Kernel::VoidPtr kInterruptVectorTable[]; + +/// @brief Kernel init function. +/// @param handover_hdr Handover boot header. +EXTERN_C Kernel::Int32 hal_init_platform(Kernel::HEL::BootInfoHeader* handover_hdr) { + using namespace Kernel; + + if (handover_hdr->f_Magic != kHandoverMagic && handover_hdr->f_Version != kHandoverVersion) { + return kEfiFail; + } + + HAL::rt_sti(); + + fw_init_efi((EfiSystemTable*) handover_hdr->f_FirmwareCustomTables[1]); + + Boot::ExitBootServices(handover_hdr->f_HardwareTables.f_ImageKey, + handover_hdr->f_HardwareTables.f_ImageHandle); + + kHandoverHeader = handover_hdr; + + kKernelVM = kHandoverHeader->f_PageStart; + + if (!kKernelVM) { + MUST_PASS(kKernelVM); + return kEfiFail; + } + + hal_write_cr3(kKernelVM); + + /************************************** */ + /* INITIALIZE BIT MAP. */ + /************************************** */ + + kBitMapCursor = 0UL; + kKernelBitMpSize = kHandoverHeader->f_BitMapSize; + kKernelBitMpStart = + reinterpret_cast(reinterpret_cast(kHandoverHeader->f_BitMapStart)); + + /************************************** */ + /* INITIALIZE GDT AND SEGMENTS. */ + /************************************** */ + + STATIC CONST auto kGDTEntriesCount = 8; + + STATIC HAL::Detail::NE_TSS kKernelTSS{}; + + kKernelTSS.fRsp0 = (UInt64) kHandoverHeader->f_StackTop; + kKernelTSS.fIopb = sizeof(HAL::Detail::NE_TSS); + + /* The GDT, mostly descriptors for user and kernel segments. */ + STATIC HAL::Detail::NE_GDT_ENTRY ALIGN(0x08) kGDTArray[kGDTEntriesCount] = { + {.fLimitLow = 0, + .fBaseLow = 0, + .fBaseMid = 0, + .fAccessByte = 0x00, + .fFlags = 0x00, + .fBaseHigh = 0}, // Null entry + {.fLimitLow = 0x0, + .fBaseLow = 0, + .fBaseMid = 0, + .fAccessByte = 0x9A, + .fFlags = 0xAF, + .fBaseHigh = 0}, // Kernel code + {.fLimitLow = 0x0, + .fBaseLow = 0, + .fBaseMid = 0, + .fAccessByte = 0x92, + .fFlags = 0xCF, + .fBaseHigh = 0}, // Kernel data + {}, // TSS data low + {}, // TSS data high + {.fLimitLow = 0x0, + .fBaseLow = 0, + .fBaseMid = 0, + .fAccessByte = 0xFA, + .fFlags = 0xAF, + .fBaseHigh = 0}, // User code + {.fLimitLow = 0x0, + .fBaseLow = 0, + .fBaseMid = 0, + .fAccessByte = 0xF2, + .fFlags = 0xCF, + .fBaseHigh = 0}, // User data + }; + + kGDTArray[3].fLimitLow = sizeof(HAL::Detail::NE_TSS) - 1; + kGDTArray[3].fBaseLow = ((UIntPtr) &kKernelTSS) & 0xFFFF; + kGDTArray[3].fBaseMid = (((UIntPtr) &kKernelTSS) >> 16) & 0xFF; + kGDTArray[3].fAccessByte = 0x89; // Present, type 9 = 64-bit available TSS + kGDTArray[3].fFlags = 0x20 | ((((UIntPtr) &kKernelTSS) >> 24) & 0x0F); + kGDTArray[3].fBaseHigh = (((UIntPtr) &kKernelTSS) >> 24) & 0xFF; + + kGDTArray[4].fLimitLow = ((UIntPtr) &kKernelTSS >> 32) & 0xFFFF; + kGDTArray[4].fBaseLow = 0; + kGDTArray[4].fBaseMid = 0; + kGDTArray[4].fAccessByte = 0; + kGDTArray[4].fFlags = 0; + kGDTArray[4].fBaseHigh = 0; + + FB::cg_clear_video(); + + // Load memory descriptors. + HAL::Register64 gdt_reg; + + gdt_reg.Base = reinterpret_cast(kGDTArray); + gdt_reg.Limit = (sizeof(HAL::Detail::NE_GDT_ENTRY) * kGDTEntriesCount) - 1; + + //! GDT will load hal_read_init after it successfully loads the segments. + HAL::GDTLoader gdt_loader; + gdt_loader.Load(gdt_reg); + + return kEfiFail; +} + +EXTERN_C Kernel::Void hal_real_init(Kernel::Void) { + HAL::mp_init_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr); + + HAL::Register64 idt_reg; + idt_reg.Base = reinterpret_cast(kInterruptVectorTable); + + HAL::IDTLoader idt_loader; + idt_loader.Load(idt_reg); + +#ifdef __FSKIT_INCLUDES_OPENHEFS__ + OpenHeFS::fs_init_openhefs(); + HeFileSystemMgr::Mount(new HeFileSystemMgr()); +#endif + +#ifdef __FSKIT_INCLUDES_NEFS__ + NeFS::fs_init_nefs(); + NeFileSystemMgr::Mount(new NeFileSystemMgr()); +#endif + + UserProcessScheduler::The().SwitchTeam(kRTUserTeam); + + PEFLoader ldr("/system/init.out"); + + if (ldr.IsLoaded()) rtl_create_user_process(ldr, UserProcess::ExecutableKind::kExecutableKind); + + UserProcessScheduler::The().SwitchTeam(kMidUserTeam); + + while (YES); +} +#endif // ifndef __NE_MODULAR_KERNEL_COMPONENTS__ diff --git a/src/kernel/HALKit/AMD64/HalKernelPanic.cc b/src/kernel/HALKit/AMD64/HalKernelPanic.cc deleted file mode 100644 index ed6a190b..00000000 --- a/src/kernel/HALKit/AMD64/HalKernelPanic.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Each error code is attributed with an ID, which will prompt a string onto the - * screen. Wait for debugger... */ - -namespace Kernel { -/// @brief Dumping factory class. -class RecoveryFactory final { - public: - STATIC Void Recover(); -}; - -/***********************************************************************************/ -/// @brief Stops execution of the kernel. -/// @param id kernel stop ID. -/***********************************************************************************/ -Void ke_panic(const Kernel::Int32& id, const Char* message) { - (Void)(kout << "*** STOP ***\r"); - - (Void)(kout << "Kernel_Panic_MSG: " << message << kendl); - (Void)(kout << "Kernel_Panic_ID: " << hex_number(id) << kendl); - (Void)(kout << "Kernel_Panic_CR2: " << hex_number((UIntPtr) hal_read_cr2()) << kendl); - - RecoveryFactory::Recover(); -} - -Void RecoveryFactory::Recover() { - while (YES) { - HAL::rt_halt(); - } -} - -void ke_runtime_check(bool expr, const Char* file, const Char* line) { - if (!expr) { - (Void)(kout << "*** CHECK ***\r"); - - (Void)(kout << "Kernel_Panic_FILE: " << file << kendl); - (Void)(kout << "Kernel_Panic_LINE: " << line << kendl); - - ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed - } -} -} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalKernelPanic.cpp b/src/kernel/HALKit/AMD64/HalKernelPanic.cpp new file mode 100644 index 00000000..ed6a190b --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalKernelPanic.cpp @@ -0,0 +1,56 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Each error code is attributed with an ID, which will prompt a string onto the + * screen. Wait for debugger... */ + +namespace Kernel { +/// @brief Dumping factory class. +class RecoveryFactory final { + public: + STATIC Void Recover(); +}; + +/***********************************************************************************/ +/// @brief Stops execution of the kernel. +/// @param id kernel stop ID. +/***********************************************************************************/ +Void ke_panic(const Kernel::Int32& id, const Char* message) { + (Void)(kout << "*** STOP ***\r"); + + (Void)(kout << "Kernel_Panic_MSG: " << message << kendl); + (Void)(kout << "Kernel_Panic_ID: " << hex_number(id) << kendl); + (Void)(kout << "Kernel_Panic_CR2: " << hex_number((UIntPtr) hal_read_cr2()) << kendl); + + RecoveryFactory::Recover(); +} + +Void RecoveryFactory::Recover() { + while (YES) { + HAL::rt_halt(); + } +} + +void ke_runtime_check(bool expr, const Char* file, const Char* line) { + if (!expr) { + (Void)(kout << "*** CHECK ***\r"); + + (Void)(kout << "Kernel_Panic_FILE: " << file << kendl); + (Void)(kout << "Kernel_Panic_LINE: " << line << kendl); + + ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed + } +} +} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalPagingMgr.cc b/src/kernel/HALKit/AMD64/HalPagingMgr.cc deleted file mode 100644 index 52561b5c..00000000 --- a/src/kernel/HALKit/AMD64/HalPagingMgr.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -namespace Kernel::HAL { -namespace Detail { - /// @brief Page Table Entry for AMD64. - struct PTE { - UInt64 Present : 1; - UInt64 Wr : 1; - UInt64 User : 1; - UInt64 Pwt : 1; // Page-level Write-Through - UInt64 Pcd : 1; // Page-level Cache Disable - UInt64 Accessed : 1; - UInt64 Dirty : 1; - UInt64 Pat : 1; // Page Attribute Table (or PS for PDE) - UInt64 Global : 1; - UInt64 Ignored1 : 3; // Available to software - UInt64 PhysicalAddress : 40; // Physical page frame address (bits 12–51) - UInt64 Ignored2 : 7; // More software bits / reserved - UInt64 ProtectionKey : 4; // Optional (if PKU enabled) - UInt64 Reserved : 1; // Usually reserved - UInt64 Nx : 1; // No Execute - }; -} // namespace Detail - -/***********************************************************************************/ -/// \brief Retrieve the page status of a PTE. -/// \param pte Page Table Entry pointer. -/***********************************************************************************/ -STATIC Void mmi_page_status(Detail::PTE* pte) { - NE_UNUSED(pte); - -#ifdef __NE_VERBOSE_BITMAP__ - (Void)(kout << "Flag: " << (pte->Present ? "Present" : "Not Present") << kendl); - (Void)(kout << "Flag: " << (pte->Wr ? "W/R" : "Not W/R") << kendl); - (Void)(kout << "Flag: " << (pte->Nx ? "NX" : "Not NX") << kendl); - (Void)(kout << "Flag: " << pte->User ? "User" : "Not User") << kendl); - (Void)(kout << "Flag: " << (pte->Pcd ? "Not Cached" : "Cached") << kendl); - (Void)(kout << "Flag: " << (pte->Accessed ? "Accessed" : "Not Accessed") << kendl); - (Void)(kout << "Flag: " << (pte->ProtectionKey ? "Protected" : "Not Protected/PKU Disabled") - << kendl); - (Void)(kout << "Physical Address: " << hex_number(pte->PhysicalAddress) << kendl); -#endif -} - -/***********************************************************************************/ -/// @brief Gets a physical address from a virtual address. -/// @param virt a valid virtual address. -/// @return Physical address. -/***********************************************************************************/ -EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virt) { - const UInt64 kVMAddr = (UInt64) virt; - const UInt64 kMask9Bits = 0x1FFULL; - const UInt64 kPageOffsetMask = 0xFFFULL; - - UInt64 cr3 = (UInt64) hal_read_cr3() & ~kPageOffsetMask; - - // Level 4 - auto pml4 = reinterpret_cast(cr3); - UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9Bits]; - - if (!(pml4e & 1)) return 0; - - // Level 3 - auto pdpt = reinterpret_cast(pml4e & ~kPageOffsetMask); - UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9Bits]; - - if (!(pdpte & 1)) return 0; - - // Level 2 - auto pd = reinterpret_cast(pdpte & ~kPageOffsetMask); - UInt64 pde = pd[(kVMAddr >> 21) & kMask9Bits]; - - if (!(pde & 1)) return 0; - - // 1 GiB page support - if (pde & (1 << 7)) { - return (pde & ~((1ULL << 30) - 1)) | (kVMAddr & ((1ULL << 30) - 1)); - } - - // Level 1 - auto pt = reinterpret_cast(pde & ~kPageOffsetMask); - Detail::PTE* pte = (Detail::PTE*) pt[(kVMAddr >> 12) & kMask9Bits]; - - if (!pte->Present) return 0; - - mmi_page_status((Detail::PTE*) pte); - - return (pte->PhysicalAddress << 12) | (kVMAddr & 0xFFF); -} - -/***********************************************************************************/ -/// @brief clflush+mfence helper function. -/***********************************************************************************/ -EXTERN_C Int32 mm_memory_fence(VoidPtr virtual_address) { - if (!virtual_address || !mm_get_page_addr(virtual_address)) return kErrorInvalidData; - - asm volatile("clflush (%0)" : : "r"(virtual_address) : "memory"); - asm volatile("mfence" ::: "memory"); - - return kErrorSuccess; -} - -/***********************************************************************************/ -/// @brief Maps or allocates a page from virtual_address. -/// @param virtual_address a valid virtual address. -/// @param phys_addr point to physical address. -/// @param flags the flags to put on the page. -/// @return Status code of page manipulation process. -/***********************************************************************************/ -EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, - UInt32 level) { - if (physical_address == 0) return kErrorInvalidData; - - NE_UNUSED(level); /// @todo support PML4, and PDPT levels. - - const UInt64 kVMAddr = (UInt64) virtual_address; - constexpr UInt64 kMask9 = 0x1FF; - constexpr UInt64 kPageMask = 0xFFF; - - UInt64 cr3 = (UIntPtr) hal_read_cr3() & ~kPageMask; - - auto pml4 = reinterpret_cast(cr3); - UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9]; - - if (!(pml4e & 1)) return kErrorInvalidData; - - UInt64* pdpt = reinterpret_cast(pml4e & ~kPageMask); - UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9]; - - if (!(pdpte & 1)) return kErrorInvalidData; - - UInt64* pd = reinterpret_cast(pdpte & ~kPageMask); - UInt64 pde = pd[(kVMAddr >> 21) & kMask9]; - - if (!(pde & 1)) return kErrorInvalidData; - - UInt64* pt = reinterpret_cast(pde & ~kPageMask); - Detail::PTE* pte = (Detail::PTE*) pt[(kVMAddr >> 12) & kMask9]; - - pte->Present = !!(flags & kMMFlagsPresent); - pte->Wr = !!(flags & kMMFlagsWr); - pte->User = !!(flags & kMMFlagsUser); - pte->Nx = !!(flags & kMMFlagsNX); - pte->Pcd = !!(flags & kMMFlagsPCD); - pte->Pwt = !!(flags & kMMFlagsPwt); - - pte->PhysicalAddress = ((UIntPtr) (physical_address)) >> 12; - - hal_invl_tlb(virtual_address); - - mm_memory_fence(virtual_address); - - mmi_page_status(pte); - - return kErrorSuccess; -} -} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalPagingMgr.cpp b/src/kernel/HALKit/AMD64/HalPagingMgr.cpp new file mode 100644 index 00000000..52561b5c --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalPagingMgr.cpp @@ -0,0 +1,162 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +namespace Kernel::HAL { +namespace Detail { + /// @brief Page Table Entry for AMD64. + struct PTE { + UInt64 Present : 1; + UInt64 Wr : 1; + UInt64 User : 1; + UInt64 Pwt : 1; // Page-level Write-Through + UInt64 Pcd : 1; // Page-level Cache Disable + UInt64 Accessed : 1; + UInt64 Dirty : 1; + UInt64 Pat : 1; // Page Attribute Table (or PS for PDE) + UInt64 Global : 1; + UInt64 Ignored1 : 3; // Available to software + UInt64 PhysicalAddress : 40; // Physical page frame address (bits 12–51) + UInt64 Ignored2 : 7; // More software bits / reserved + UInt64 ProtectionKey : 4; // Optional (if PKU enabled) + UInt64 Reserved : 1; // Usually reserved + UInt64 Nx : 1; // No Execute + }; +} // namespace Detail + +/***********************************************************************************/ +/// \brief Retrieve the page status of a PTE. +/// \param pte Page Table Entry pointer. +/***********************************************************************************/ +STATIC Void mmi_page_status(Detail::PTE* pte) { + NE_UNUSED(pte); + +#ifdef __NE_VERBOSE_BITMAP__ + (Void)(kout << "Flag: " << (pte->Present ? "Present" : "Not Present") << kendl); + (Void)(kout << "Flag: " << (pte->Wr ? "W/R" : "Not W/R") << kendl); + (Void)(kout << "Flag: " << (pte->Nx ? "NX" : "Not NX") << kendl); + (Void)(kout << "Flag: " << pte->User ? "User" : "Not User") << kendl); + (Void)(kout << "Flag: " << (pte->Pcd ? "Not Cached" : "Cached") << kendl); + (Void)(kout << "Flag: " << (pte->Accessed ? "Accessed" : "Not Accessed") << kendl); + (Void)(kout << "Flag: " << (pte->ProtectionKey ? "Protected" : "Not Protected/PKU Disabled") + << kendl); + (Void)(kout << "Physical Address: " << hex_number(pte->PhysicalAddress) << kendl); +#endif +} + +/***********************************************************************************/ +/// @brief Gets a physical address from a virtual address. +/// @param virt a valid virtual address. +/// @return Physical address. +/***********************************************************************************/ +EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virt) { + const UInt64 kVMAddr = (UInt64) virt; + const UInt64 kMask9Bits = 0x1FFULL; + const UInt64 kPageOffsetMask = 0xFFFULL; + + UInt64 cr3 = (UInt64) hal_read_cr3() & ~kPageOffsetMask; + + // Level 4 + auto pml4 = reinterpret_cast(cr3); + UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9Bits]; + + if (!(pml4e & 1)) return 0; + + // Level 3 + auto pdpt = reinterpret_cast(pml4e & ~kPageOffsetMask); + UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9Bits]; + + if (!(pdpte & 1)) return 0; + + // Level 2 + auto pd = reinterpret_cast(pdpte & ~kPageOffsetMask); + UInt64 pde = pd[(kVMAddr >> 21) & kMask9Bits]; + + if (!(pde & 1)) return 0; + + // 1 GiB page support + if (pde & (1 << 7)) { + return (pde & ~((1ULL << 30) - 1)) | (kVMAddr & ((1ULL << 30) - 1)); + } + + // Level 1 + auto pt = reinterpret_cast(pde & ~kPageOffsetMask); + Detail::PTE* pte = (Detail::PTE*) pt[(kVMAddr >> 12) & kMask9Bits]; + + if (!pte->Present) return 0; + + mmi_page_status((Detail::PTE*) pte); + + return (pte->PhysicalAddress << 12) | (kVMAddr & 0xFFF); +} + +/***********************************************************************************/ +/// @brief clflush+mfence helper function. +/***********************************************************************************/ +EXTERN_C Int32 mm_memory_fence(VoidPtr virtual_address) { + if (!virtual_address || !mm_get_page_addr(virtual_address)) return kErrorInvalidData; + + asm volatile("clflush (%0)" : : "r"(virtual_address) : "memory"); + asm volatile("mfence" ::: "memory"); + + return kErrorSuccess; +} + +/***********************************************************************************/ +/// @brief Maps or allocates a page from virtual_address. +/// @param virtual_address a valid virtual address. +/// @param phys_addr point to physical address. +/// @param flags the flags to put on the page. +/// @return Status code of page manipulation process. +/***********************************************************************************/ +EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, + UInt32 level) { + if (physical_address == 0) return kErrorInvalidData; + + NE_UNUSED(level); /// @todo support PML4, and PDPT levels. + + const UInt64 kVMAddr = (UInt64) virtual_address; + constexpr UInt64 kMask9 = 0x1FF; + constexpr UInt64 kPageMask = 0xFFF; + + UInt64 cr3 = (UIntPtr) hal_read_cr3() & ~kPageMask; + + auto pml4 = reinterpret_cast(cr3); + UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9]; + + if (!(pml4e & 1)) return kErrorInvalidData; + + UInt64* pdpt = reinterpret_cast(pml4e & ~kPageMask); + UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9]; + + if (!(pdpte & 1)) return kErrorInvalidData; + + UInt64* pd = reinterpret_cast(pdpte & ~kPageMask); + UInt64 pde = pd[(kVMAddr >> 21) & kMask9]; + + if (!(pde & 1)) return kErrorInvalidData; + + UInt64* pt = reinterpret_cast(pde & ~kPageMask); + Detail::PTE* pte = (Detail::PTE*) pt[(kVMAddr >> 12) & kMask9]; + + pte->Present = !!(flags & kMMFlagsPresent); + pte->Wr = !!(flags & kMMFlagsWr); + pte->User = !!(flags & kMMFlagsUser); + pte->Nx = !!(flags & kMMFlagsNX); + pte->Pcd = !!(flags & kMMFlagsPCD); + pte->Pwt = !!(flags & kMMFlagsPwt); + + pte->PhysicalAddress = ((UIntPtr) (physical_address)) >> 12; + + hal_invl_tlb(virtual_address); + + mm_memory_fence(virtual_address); + + mmi_page_status(pte); + + return kErrorSuccess; +} +} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalProcessor.cc b/src/kernel/HALKit/AMD64/HalProcessor.cc deleted file mode 100644 index 50c2ca53..00000000 --- a/src/kernel/HALKit/AMD64/HalProcessor.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -/** - * @file HalCPU.cc - * @brief Common CPU API. - */ - -namespace Kernel::HAL { -inline Bool hal_has_msr() { - static UInt32 eax, unused, edx; // eax, edx - - __get_cpuid(1, &eax, &unused, &unused, &edx); - - // edx returns the flag for MSR (which is 1 shifted to 5.) - return edx & (1 << 5); -} - -Void hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) { - if (!lo || !hi) return; - asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr)); -} - -Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) { - asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr)); -} - -Void lrt_hal_out8(UInt16 port, UInt8 value) { - asm volatile("outb %%al, %1" : : "a"(value), "Nd"(port) : "memory"); -} - -Void lrt_hal_out16(UInt16 port, UInt16 value) { - asm volatile("outw %%ax, %1" : : "a"(value), "Nd"(port) : "memory"); -} - -Void lrt_hal_out32(UInt16 port, UInt32 value) { - asm volatile("outl %%eax, %1" : : "a"(value), "Nd"(port) : "memory"); -} - -UInt8 lrt_hal_in8(UInt16 port) { - UInt8 value = 0UL; - asm volatile("inb %1, %%al" : "=a"(value) : "Nd"(port) : "memory"); - - return value; -} - -UInt16 lrt_hal_in16(UInt16 port) { - UInt16 value = 0UL; - asm volatile("inw %1, %%ax" : "=a"(value) : "Nd"(port) : "memory"); - - return value; -} - -UInt32 lrt_hal_in32(UInt16 port) { - UInt32 value = 0UL; - asm volatile("inl %1, %%eax" : "=a"(value) : "Nd"(port) : "memory"); - - return value; -} - -Void rt_halt() { - asm volatile("hlt"); -} - -Void rt_cli() { - asm volatile("cli"); -} - -Void rt_sti() { - asm volatile("sti"); -} - -Void rt_cld() { - asm volatile("cld"); -} - -Void rt_std() { - asm volatile("std"); -} -} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalProcessor.cpp b/src/kernel/HALKit/AMD64/HalProcessor.cpp new file mode 100644 index 00000000..50c2ca53 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalProcessor.cpp @@ -0,0 +1,84 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +/** + * @file HalCPU.cc + * @brief Common CPU API. + */ + +namespace Kernel::HAL { +inline Bool hal_has_msr() { + static UInt32 eax, unused, edx; // eax, edx + + __get_cpuid(1, &eax, &unused, &unused, &edx); + + // edx returns the flag for MSR (which is 1 shifted to 5.) + return edx & (1 << 5); +} + +Void hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) { + if (!lo || !hi) return; + asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr)); +} + +Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) { + asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr)); +} + +Void lrt_hal_out8(UInt16 port, UInt8 value) { + asm volatile("outb %%al, %1" : : "a"(value), "Nd"(port) : "memory"); +} + +Void lrt_hal_out16(UInt16 port, UInt16 value) { + asm volatile("outw %%ax, %1" : : "a"(value), "Nd"(port) : "memory"); +} + +Void lrt_hal_out32(UInt16 port, UInt32 value) { + asm volatile("outl %%eax, %1" : : "a"(value), "Nd"(port) : "memory"); +} + +UInt8 lrt_hal_in8(UInt16 port) { + UInt8 value = 0UL; + asm volatile("inb %1, %%al" : "=a"(value) : "Nd"(port) : "memory"); + + return value; +} + +UInt16 lrt_hal_in16(UInt16 port) { + UInt16 value = 0UL; + asm volatile("inw %1, %%ax" : "=a"(value) : "Nd"(port) : "memory"); + + return value; +} + +UInt32 lrt_hal_in32(UInt16 port) { + UInt32 value = 0UL; + asm volatile("inl %1, %%eax" : "=a"(value) : "Nd"(port) : "memory"); + + return value; +} + +Void rt_halt() { + asm volatile("hlt"); +} + +Void rt_cli() { + asm volatile("cli"); +} + +Void rt_sti() { + asm volatile("sti"); +} + +Void rt_cld() { + asm volatile("cld"); +} + +Void rt_std() { + asm volatile("std"); +} +} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc b/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc deleted file mode 100644 index 3571d2af..00000000 --- a/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -namespace Kernel { -/***********************************************************************************/ -/// @brief Unimplemented function (crashes by default) -/// @param -/***********************************************************************************/ - -EXTERN_C Void __ne_pure_call(UserProcess* process) { - if (process) process->Crash(); -} - -/***********************************************************************************/ -/// @brief Validate user stack. -/// @param stack_ptr the frame pointer. -/***********************************************************************************/ - -EXTERN_C Bool hal_check_task(HAL::StackFramePtr stack_ptr) { - if (!stack_ptr) return No; - - return stack_ptr->SP > 0 && stack_ptr->IP > 0; -} - -/// @brief Wakes up thread. -/// Wakes up thread from the hang state. -Void mp_wakeup_thread(HAL::StackFrame* stack) { - if (!hal_check_task(stack)) return; - - // RIP is always in R15. R15 is reserved for the RIP. - stack->IP = stack->R15; - - Kernel::UserProcessHelper::StartScheduling(); -} - -/// @brief makes the thread sleep on a loop. -/// hooks and hangs thread to prevent code from executing. -Void mp_hang_thread(HAL::StackFrame* stack) { - if (!hal_check_task(stack)) return; - - // Store IP in R15 - stack->R15 = stack->IP; - stack->IP = 0UL; -} -} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cpp b/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cpp new file mode 100644 index 00000000..3571d2af --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cpp @@ -0,0 +1,49 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +namespace Kernel { +/***********************************************************************************/ +/// @brief Unimplemented function (crashes by default) +/// @param +/***********************************************************************************/ + +EXTERN_C Void __ne_pure_call(UserProcess* process) { + if (process) process->Crash(); +} + +/***********************************************************************************/ +/// @brief Validate user stack. +/// @param stack_ptr the frame pointer. +/***********************************************************************************/ + +EXTERN_C Bool hal_check_task(HAL::StackFramePtr stack_ptr) { + if (!stack_ptr) return No; + + return stack_ptr->SP > 0 && stack_ptr->IP > 0; +} + +/// @brief Wakes up thread. +/// Wakes up thread from the hang state. +Void mp_wakeup_thread(HAL::StackFrame* stack) { + if (!hal_check_task(stack)) return; + + // RIP is always in R15. R15 is reserved for the RIP. + stack->IP = stack->R15; + + Kernel::UserProcessHelper::StartScheduling(); +} + +/// @brief makes the thread sleep on a loop. +/// hooks and hangs thread to prevent code from executing. +Void mp_hang_thread(HAL::StackFrame* stack) { + if (!hal_check_task(stack)) return; + + // Store IP in R15 + stack->R15 = stack->IP; + stack->IP = 0UL; +} +} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/HalTimer.cc b/src/kernel/HALKit/AMD64/HalTimer.cc deleted file mode 100644 index 275c1ece..00000000 --- a/src/kernel/HALKit/AMD64/HalTimer.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -/// ================================================================================ -/// @note timer slot 0 -/// ================================================================================ - -#define kHPETSignature ("HPET") - -#define kHPETCounterRegValue (0x00) -#define kHPETConfigRegValue (0x20) -#define kHPETCompRegValue (0x24) -#define kHPETInterruptRegValue (0x2C) - -/// ================================================================================ -///! BUGS: 0 -///! @file HalTimer.cc -///! @brief Hardware Timer (HPET) -/// ================================================================================ - -namespace Kernel::Detail { -struct HPET_BLOCK : public Kernel::SDT { - Kernel::UInt8 hardware_rev_id; - Kernel::UInt8 comparator_count : 5; - Kernel::UInt8 counter_size : 1; - Kernel::UInt8 reserved : 1; - Kernel::UInt8 legacy_replacement : 1; - Kernel::UInt16 pci_vendor_id; - ACPI_ADDRESS address; - Kernel::UInt8 hpet_number; - Kernel::UInt16 minimum_tick; - Kernel::UInt8 page_protection; -} PACKED; -} // namespace Kernel::Detail - -using namespace Kernel; - -HardwareTimer::HardwareTimer(UInt64 ms) : fWaitFor(ms) { - auto power = PowerFactoryInterface(kHandoverHeader->f_HardwareTables.f_VendorPtr); - - auto hpet = (Detail::HPET_BLOCK*) power.Find(kHPETSignature).Leak().Leak(); - MUST_PASS(hpet); - - fDigitalTimer = (UInt8*) hpet->address.Address; - - if (hpet->page_protection) { - HAL::mm_map_page((VoidPtr) fDigitalTimer, (VoidPtr) fDigitalTimer, - HAL::kMMFlagsWr | HAL::kMMFlagsPCD | HAL::kMMFlagsPwt); - } - - // if not enabled yet. - if (!(*((volatile UInt64*) ((UInt8*) fDigitalTimer + kHPETConfigRegValue)) & (1 << 0))) { - *((volatile UInt64*) ((UInt8*) fDigitalTimer + kHPETConfigRegValue)) = - *((volatile UInt64*) ((UInt8*) fDigitalTimer + kHPETConfigRegValue)) | (1 << 0) | - (1 << 3); // enable timer & one shot conf - } -} - -HardwareTimer::~HardwareTimer() { - fDigitalTimer = nullptr; - fWaitFor = 0; -} - -/***********************************************************************************/ -/// @brief Wait for the timer to stop spinning. -/***********************************************************************************/ - -BOOL HardwareTimer::Wait() { - if (fWaitFor < 1) return NO; - if (fWaitFor > 1'000'000) return NO; // max 1000s = 16 minutes - - UInt64 hpet_cap = *((volatile UInt64*) (fDigitalTimer)); - UInt64 femtoseconds_per_tick = (hpet_cap >> 32); - - if (femtoseconds_per_tick == 0) return NO; - - volatile UInt64* timer = (volatile UInt64*) (fDigitalTimer + kHPETCounterRegValue); - - UInt64 now = *timer; - - UInt64 fs_wait = fWaitFor * 1'000'000'000'000ULL; - UInt64 stop_at = now + (fs_wait / femtoseconds_per_tick); - - while (*timer < (stop_at)) asm volatile("pause"); - - return YES; -} diff --git a/src/kernel/HALKit/AMD64/HalTimer.cpp b/src/kernel/HALKit/AMD64/HalTimer.cpp new file mode 100644 index 00000000..275c1ece --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalTimer.cpp @@ -0,0 +1,92 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +/// ================================================================================ +/// @note timer slot 0 +/// ================================================================================ + +#define kHPETSignature ("HPET") + +#define kHPETCounterRegValue (0x00) +#define kHPETConfigRegValue (0x20) +#define kHPETCompRegValue (0x24) +#define kHPETInterruptRegValue (0x2C) + +/// ================================================================================ +///! BUGS: 0 +///! @file HalTimer.cc +///! @brief Hardware Timer (HPET) +/// ================================================================================ + +namespace Kernel::Detail { +struct HPET_BLOCK : public Kernel::SDT { + Kernel::UInt8 hardware_rev_id; + Kernel::UInt8 comparator_count : 5; + Kernel::UInt8 counter_size : 1; + Kernel::UInt8 reserved : 1; + Kernel::UInt8 legacy_replacement : 1; + Kernel::UInt16 pci_vendor_id; + ACPI_ADDRESS address; + Kernel::UInt8 hpet_number; + Kernel::UInt16 minimum_tick; + Kernel::UInt8 page_protection; +} PACKED; +} // namespace Kernel::Detail + +using namespace Kernel; + +HardwareTimer::HardwareTimer(UInt64 ms) : fWaitFor(ms) { + auto power = PowerFactoryInterface(kHandoverHeader->f_HardwareTables.f_VendorPtr); + + auto hpet = (Detail::HPET_BLOCK*) power.Find(kHPETSignature).Leak().Leak(); + MUST_PASS(hpet); + + fDigitalTimer = (UInt8*) hpet->address.Address; + + if (hpet->page_protection) { + HAL::mm_map_page((VoidPtr) fDigitalTimer, (VoidPtr) fDigitalTimer, + HAL::kMMFlagsWr | HAL::kMMFlagsPCD | HAL::kMMFlagsPwt); + } + + // if not enabled yet. + if (!(*((volatile UInt64*) ((UInt8*) fDigitalTimer + kHPETConfigRegValue)) & (1 << 0))) { + *((volatile UInt64*) ((UInt8*) fDigitalTimer + kHPETConfigRegValue)) = + *((volatile UInt64*) ((UInt8*) fDigitalTimer + kHPETConfigRegValue)) | (1 << 0) | + (1 << 3); // enable timer & one shot conf + } +} + +HardwareTimer::~HardwareTimer() { + fDigitalTimer = nullptr; + fWaitFor = 0; +} + +/***********************************************************************************/ +/// @brief Wait for the timer to stop spinning. +/***********************************************************************************/ + +BOOL HardwareTimer::Wait() { + if (fWaitFor < 1) return NO; + if (fWaitFor > 1'000'000) return NO; // max 1000s = 16 minutes + + UInt64 hpet_cap = *((volatile UInt64*) (fDigitalTimer)); + UInt64 femtoseconds_per_tick = (hpet_cap >> 32); + + if (femtoseconds_per_tick == 0) return NO; + + volatile UInt64* timer = (volatile UInt64*) (fDigitalTimer + kHPETCounterRegValue); + + UInt64 now = *timer; + + UInt64 fs_wait = fWaitFor * 1'000'000'000'000ULL; + UInt64 stop_at = now + (fs_wait / femtoseconds_per_tick); + + while (*timer < (stop_at)) asm volatile("pause"); + + return YES; +} diff --git a/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc b/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc deleted file mode 100644 index 2f6cc6da..00000000 --- a/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -using namespace Kernel; -using namespace Kernel::HAL; - -STATIC UInt16 kRTLIOBase = 0xFFFF; - -STATIC BOOL kTXRXEnabled = NO; - -STATIC UInt32 kRXOffset = 0UL; -STATIC constexpr CONST UInt32 kRXBufferSize = 8192 + 16 + 1500; - -STATIC UInt8* kRXUpperLayer = nullptr; -STATIC UInt8* kRXBuffer = nullptr; - -/***********************************************************************************/ -///@brief RTL8139 Init routine. -/***********************************************************************************/ - -EXTERN_C BOOL rtl_init_nic_rtl8139(UInt16 io_base) { - if (kTXRXEnabled) return NO; - - kRTLIOBase = io_base; - - MUST_PASS(io_base != 0xFFFF); - - kRXBuffer = reinterpret_cast(rtl_dma_alloc(sizeof(UInt8) * kRXBufferSize, 0)); - - MUST_PASS(kRXBuffer); - - /// Reset first. - - rt_out8(io_base + 0x37, 0x10); - - UInt16 timeout = 0U; - - while (rt_in8(io_base + 0x37) & 0x10) { - ++timeout; - if (timeout > 0x1000) break; - } - - if (timeout <= 0x1000) { - return NO; - } - - rt_out32(io_base + 0x30, (UInt32) (UIntPtr) kRXBuffer); - - rt_out8(io_base + 0x37, 0x0C); - - rt_out32(io_base + 0x44, 0xF | (1 << 7)); - - rt_out16(io_base + 0x3C, 0x0005); - - kTXRXEnabled = YES; - - return YES; -} - -/***********************************************************************************/ -/// @brief RTL8139 I/O interrupt handler. -/// @param rsp stack pointer. -/// @note This function is called when the device interrupts to retrieve network data. -/***********************************************************************************/ - -EXTERN_C Void rtl_rtl8139_interrupt_handler(UIntPtr rsp) { - if (kRTLIOBase == 0xFFFF || kRTLIOBase == 0) return; - - NE_UNUSED(rsp); - - UInt16 status = rt_in16(kRTLIOBase + 0x3E); - rt_out16(kRTLIOBase + 0x3E, status); - - if (status & 0x01) { - // While we receive data. - while ((rt_in8(kRTLIOBase + 0x37) & 0x01) == 0) { - // We grab an offset from the RX buffer. - UInt32 offset = kRXOffset % kRXBufferSize; - - // If the offset is too high, we reset it. - if (offset >= (kRXBufferSize - 16)) { - kRXOffset = 0UL; - offset = 0UL; - } - - volatile UInt8* packet = kRXBuffer + offset + 4; - UInt16 len = *(UInt16*) (kRXBuffer + offset + 2); - - kRXUpperLayer[(offset + 4)] = *packet; - kRXOffset += (len + 4); - - rt_out16(kRTLIOBase + 0x38, (UInt16) (kRXOffset - 16)); - } - } - - if (!(status & 0x04)) { - err_global_get() = kErrorNoNetwork; - } -} - -/***********************************************************************************/ -/// @brief RTL8139 get upper layer function -/// @return the upper layer. -/// @retval nullptr if no upper layer is set. -/// @retval pointer to the upper layer if set. -/***********************************************************************************/ - -EXTERN_C UInt8* rtl_rtl8139_get_upper_layer() { - return kRXUpperLayer; -} - -/***********************************************************************************/ -/// @brief RTL8139 set upper layer function -/// @param layer the upper layer. -/***********************************************************************************/ - -EXTERN_C BOOL rtl_rtl8139_set_upper_layer(UInt8* layer) { - if (!layer) return NO; - kRXUpperLayer = layer; - - return YES; -} diff --git a/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cpp b/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cpp new file mode 100644 index 00000000..2f6cc6da --- /dev/null +++ b/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cpp @@ -0,0 +1,127 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +using namespace Kernel; +using namespace Kernel::HAL; + +STATIC UInt16 kRTLIOBase = 0xFFFF; + +STATIC BOOL kTXRXEnabled = NO; + +STATIC UInt32 kRXOffset = 0UL; +STATIC constexpr CONST UInt32 kRXBufferSize = 8192 + 16 + 1500; + +STATIC UInt8* kRXUpperLayer = nullptr; +STATIC UInt8* kRXBuffer = nullptr; + +/***********************************************************************************/ +///@brief RTL8139 Init routine. +/***********************************************************************************/ + +EXTERN_C BOOL rtl_init_nic_rtl8139(UInt16 io_base) { + if (kTXRXEnabled) return NO; + + kRTLIOBase = io_base; + + MUST_PASS(io_base != 0xFFFF); + + kRXBuffer = reinterpret_cast(rtl_dma_alloc(sizeof(UInt8) * kRXBufferSize, 0)); + + MUST_PASS(kRXBuffer); + + /// Reset first. + + rt_out8(io_base + 0x37, 0x10); + + UInt16 timeout = 0U; + + while (rt_in8(io_base + 0x37) & 0x10) { + ++timeout; + if (timeout > 0x1000) break; + } + + if (timeout <= 0x1000) { + return NO; + } + + rt_out32(io_base + 0x30, (UInt32) (UIntPtr) kRXBuffer); + + rt_out8(io_base + 0x37, 0x0C); + + rt_out32(io_base + 0x44, 0xF | (1 << 7)); + + rt_out16(io_base + 0x3C, 0x0005); + + kTXRXEnabled = YES; + + return YES; +} + +/***********************************************************************************/ +/// @brief RTL8139 I/O interrupt handler. +/// @param rsp stack pointer. +/// @note This function is called when the device interrupts to retrieve network data. +/***********************************************************************************/ + +EXTERN_C Void rtl_rtl8139_interrupt_handler(UIntPtr rsp) { + if (kRTLIOBase == 0xFFFF || kRTLIOBase == 0) return; + + NE_UNUSED(rsp); + + UInt16 status = rt_in16(kRTLIOBase + 0x3E); + rt_out16(kRTLIOBase + 0x3E, status); + + if (status & 0x01) { + // While we receive data. + while ((rt_in8(kRTLIOBase + 0x37) & 0x01) == 0) { + // We grab an offset from the RX buffer. + UInt32 offset = kRXOffset % kRXBufferSize; + + // If the offset is too high, we reset it. + if (offset >= (kRXBufferSize - 16)) { + kRXOffset = 0UL; + offset = 0UL; + } + + volatile UInt8* packet = kRXBuffer + offset + 4; + UInt16 len = *(UInt16*) (kRXBuffer + offset + 2); + + kRXUpperLayer[(offset + 4)] = *packet; + kRXOffset += (len + 4); + + rt_out16(kRTLIOBase + 0x38, (UInt16) (kRXOffset - 16)); + } + } + + if (!(status & 0x04)) { + err_global_get() = kErrorNoNetwork; + } +} + +/***********************************************************************************/ +/// @brief RTL8139 get upper layer function +/// @return the upper layer. +/// @retval nullptr if no upper layer is set. +/// @retval pointer to the upper layer if set. +/***********************************************************************************/ + +EXTERN_C UInt8* rtl_rtl8139_get_upper_layer() { + return kRXUpperLayer; +} + +/***********************************************************************************/ +/// @brief RTL8139 set upper layer function +/// @param layer the upper layer. +/***********************************************************************************/ + +EXTERN_C BOOL rtl_rtl8139_set_upper_layer(UInt8* layer) { + if (!layer) return NO; + kRXUpperLayer = layer; + + return YES; +} diff --git a/src/kernel/HALKit/AMD64/PCI/DMA.cc b/src/kernel/HALKit/AMD64/PCI/DMA.cc deleted file mode 100644 index 73e5e401..00000000 --- a/src/kernel/HALKit/AMD64/PCI/DMA.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -namespace Kernel { -DMAWrapper::operator bool() { - return this->fAddress; -} - -bool DMAWrapper::operator!() { - return !this->fAddress; -} - -Boolean DMAWrapper::Check(UIntPtr offset) const { - if (!this->fAddress) return false; - - if (offset == 0) return false; - - kout << "[DMAWrapper::IsIn] Checking offset...\r"; - return reinterpret_cast(this->fAddress) >= offset; -} - -bool DMAWrapper::Write(UIntPtr& bit, const UInt32& offset) { - kout << "[DMAWrapper::Read] Checking this->fAddress...\r"; - - if (!this->fAddress) return false; - - (Void)(kout << "[DMAWrapper::Write] Writing at address: " - << hex_number(reinterpret_cast(this->fAddress) + offset) << kendl); - - ke_dma_write(reinterpret_cast(this->fAddress), offset, bit); - - return true; -} - -UIntPtr DMAWrapper::Read(const UInt32& offset) { - kout << "[DMAWrapper::Read] Checking this->fAddress...\r"; - - if (!this->fAddress) return ~0; - - (Void)(kout << "[DMAWrapper::Write] Writing at address: " - << hex_number(reinterpret_cast(this->fAddress) + offset) << kendl); - - return (UIntPtr) ke_dma_read(reinterpret_cast(this->fAddress), offset); -} - -UIntPtr DMAWrapper::operator[](UIntPtr& offset) { - return this->Read(offset); -} - -OwnPtr> DMAFactory::Construct(OwnPtr& dma) { - if (!dma) return {}; - - OwnPtr> dmaOwnPtr = - make_ptr, char*>(reinterpret_cast(dma->fAddress)); - - if (!dmaOwnPtr) return {}; - - kout << "Returning the new OwnPtr>!\r"; - return dmaOwnPtr; -} - -DMAWrapper& DMAWrapper::operator=(voidPtr Ptr) { - this->fAddress = Ptr; - return *this; -} -} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/PCI/DMA.cpp b/src/kernel/HALKit/AMD64/PCI/DMA.cpp new file mode 100644 index 00000000..73e5e401 --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/DMA.cpp @@ -0,0 +1,70 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +namespace Kernel { +DMAWrapper::operator bool() { + return this->fAddress; +} + +bool DMAWrapper::operator!() { + return !this->fAddress; +} + +Boolean DMAWrapper::Check(UIntPtr offset) const { + if (!this->fAddress) return false; + + if (offset == 0) return false; + + kout << "[DMAWrapper::IsIn] Checking offset...\r"; + return reinterpret_cast(this->fAddress) >= offset; +} + +bool DMAWrapper::Write(UIntPtr& bit, const UInt32& offset) { + kout << "[DMAWrapper::Read] Checking this->fAddress...\r"; + + if (!this->fAddress) return false; + + (Void)(kout << "[DMAWrapper::Write] Writing at address: " + << hex_number(reinterpret_cast(this->fAddress) + offset) << kendl); + + ke_dma_write(reinterpret_cast(this->fAddress), offset, bit); + + return true; +} + +UIntPtr DMAWrapper::Read(const UInt32& offset) { + kout << "[DMAWrapper::Read] Checking this->fAddress...\r"; + + if (!this->fAddress) return ~0; + + (Void)(kout << "[DMAWrapper::Write] Writing at address: " + << hex_number(reinterpret_cast(this->fAddress) + offset) << kendl); + + return (UIntPtr) ke_dma_read(reinterpret_cast(this->fAddress), offset); +} + +UIntPtr DMAWrapper::operator[](UIntPtr& offset) { + return this->Read(offset); +} + +OwnPtr> DMAFactory::Construct(OwnPtr& dma) { + if (!dma) return {}; + + OwnPtr> dmaOwnPtr = + make_ptr, char*>(reinterpret_cast(dma->fAddress)); + + if (!dmaOwnPtr) return {}; + + kout << "Returning the new OwnPtr>!\r"; + return dmaOwnPtr; +} + +DMAWrapper& DMAWrapper::operator=(voidPtr Ptr) { + this->fAddress = Ptr; + return *this; +} +} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/PCI/Database.cc b/src/kernel/HALKit/AMD64/PCI/Database.cc deleted file mode 100644 index 7eb098da..00000000 --- a/src/kernel/HALKit/AMD64/PCI/Database.cc +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -namespace Kernel {} diff --git a/src/kernel/HALKit/AMD64/PCI/Database.cpp b/src/kernel/HALKit/AMD64/PCI/Database.cpp new file mode 100644 index 00000000..7eb098da --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/Database.cpp @@ -0,0 +1,7 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +namespace Kernel {} diff --git a/src/kernel/HALKit/AMD64/PCI/Device.cc b/src/kernel/HALKit/AMD64/PCI/Device.cc deleted file mode 100644 index dcc16e6a..00000000 --- a/src/kernel/HALKit/AMD64/PCI/Device.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -#define PCI_BAR_IO (0x01) -#define PCI_BAR_LOWMEM (0x02) -#define PCI_BAR_64 (0x04) -#define PCI_BAR_PREFETCH (0x08) -#define PCI_ENABLE_BIT (0x80000000) - -static Kernel::UInt NE_PCIReadRaw(Kernel::UInt bar, Kernel::UShort bus, Kernel::UShort dev, - Kernel::UShort fun) { - Kernel::UInt target = PCI_ENABLE_BIT | ((Kernel::UInt) bus << 16) | ((Kernel::UInt) dev << 11) | - ((Kernel::UInt) fun << 8) | (bar & 0xFC); - - Kernel::HAL::rt_out32((Kernel::UShort) Kernel::PCI::PciConfigKind::ConfigAddress, target); - - Kernel::HAL::rt_wait_400ns(); - - return Kernel::HAL::rt_in32((Kernel::UShort) Kernel::PCI::PciConfigKind::ConfigData); -} - -static Kernel::Void NE_PCISetCfgTarget(Kernel::UInt bar, Kernel::UShort bus, Kernel::UShort dev, - Kernel::UShort fun) { - Kernel::UInt target = 0x80000000 | ((Kernel::UInt) bus << 16) | ((Kernel::UInt) dev << 11) | - ((Kernel::UInt) fun << 8) | (bar & 0xFC); - - Kernel::HAL::rt_out32((Kernel::UShort) Kernel::PCI::PciConfigKind::ConfigAddress, target); - - Kernel::HAL::rt_wait_400ns(); -} - -namespace Kernel::PCI { -Device::Device(UShort bus, UShort device, UShort func, UInt32 bar) - : fBus(bus), fDevice(device), fFunction(func), fBar(bar) {} - -Device::~Device() = default; - -UInt Device::Read(UInt bar, Size sz) { - // Ensure aligned access by masking to 4-byte boundary - NE_PCISetCfgTarget(bar & 0xFC, fBus, fDevice, fFunction); - - // Read 4 bytes and shift out the correct value - UInt data = HAL::rt_in32((UShort) PciConfigKind::ConfigData); - - if (sz == 4) return data; - if (sz == 2) return (data >> ((bar & 2) * 8)) & 0xFFFF; - if (sz == 1) return (data >> ((bar & 3) * 8)) & 0xFF; - - return (UShort) PciConfigKind::Invalid; -} - -void Device::Write(UInt bar, UIntPtr data, Size sz) { - NE_PCISetCfgTarget(bar & 0xFC, fBus, fDevice, fFunction); - - if (sz == 4) { - HAL::rt_out32((UShort) PciConfigKind::ConfigAddress, (UInt) data); - } else if (sz == 2) { - UInt temp = HAL::rt_in32((UShort) PciConfigKind::ConfigData); - - temp &= ~(0xFFFF << ((bar & 2) * 8)); - temp |= (data & 0xFFFF) << ((bar & 2) * 8); - - HAL::rt_out32((UShort) PciConfigKind::ConfigAddress, temp); - } else if (sz == 1) { - UInt temp = HAL::rt_in32((UShort) PciConfigKind::ConfigData); - - temp &= ~(0xFF << ((bar & 3) * 8)); - temp |= (data & 0xFF) << ((bar & 3) * 8); - - HAL::rt_out32((UShort) PciConfigKind::ConfigAddress, temp); - } -} - -UShort Device::DeviceId() { - return (UShort) (NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) >> 16); -} - -UShort Device::VendorId() { - return (UShort) (NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) & 0xFFFF); -} - -UShort Device::InterfaceId() { - return (UShort) (NE_PCIReadRaw(0x09, fBus, fDevice, fFunction) >> 16); -} - -UChar Device::Class() { - return (UChar) (NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 24); -} - -UChar Device::Subclass() { - return (UChar) (NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 16); -} - -UChar Device::ProgIf() { - return (UChar) (NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 8); -} - -UChar Device::HeaderType() { - return (UChar) (NE_PCIReadRaw(0xC, fBus, fDevice, fFunction) >> 16); -} - -void Device::EnableMmio() { - UInt32 command = Read(0x04, sizeof(UInt32)); - command |= (1 << 1); // Memory Space Enable (bit 1) - - Write(0x04, command, sizeof(UInt32)); -} - -void Device::BecomeBusMaster() { - UInt32 command = Read(0x04, sizeof(UInt32)); - command |= (1 << 2); // Bus Master Enable (bit 2) - Write(0x04, command, sizeof(UInt32)); -} - -UIntPtr Device::Bar(UInt32 bar_in) { - UInt32 bar = NE_PCIReadRaw(bar_in, fBus, fDevice, fFunction); - - if (bar & PCI_BAR_IO) return static_cast(bar & ~0x03); - - if (bar & PCI_BAR_64) { - UInt32 high = NE_PCIReadRaw((bar_in + 4) & ~0x03, fBus, fDevice, fFunction); - return (static_cast(high) << 32) | (bar & ~0x0F); - } - - return static_cast(bar & ~0x0F); -} - -UShort Device::Vendor() { - UShort vendor = this->VendorId(); - return vendor; -} - -Device::operator bool() { - return this->VendorId() != (UShort) PciConfigKind::Invalid; -} -} // namespace Kernel::PCI diff --git a/src/kernel/HALKit/AMD64/PCI/Device.cpp b/src/kernel/HALKit/AMD64/PCI/Device.cpp new file mode 100644 index 00000000..dcc16e6a --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/Device.cpp @@ -0,0 +1,140 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +#define PCI_BAR_IO (0x01) +#define PCI_BAR_LOWMEM (0x02) +#define PCI_BAR_64 (0x04) +#define PCI_BAR_PREFETCH (0x08) +#define PCI_ENABLE_BIT (0x80000000) + +static Kernel::UInt NE_PCIReadRaw(Kernel::UInt bar, Kernel::UShort bus, Kernel::UShort dev, + Kernel::UShort fun) { + Kernel::UInt target = PCI_ENABLE_BIT | ((Kernel::UInt) bus << 16) | ((Kernel::UInt) dev << 11) | + ((Kernel::UInt) fun << 8) | (bar & 0xFC); + + Kernel::HAL::rt_out32((Kernel::UShort) Kernel::PCI::PciConfigKind::ConfigAddress, target); + + Kernel::HAL::rt_wait_400ns(); + + return Kernel::HAL::rt_in32((Kernel::UShort) Kernel::PCI::PciConfigKind::ConfigData); +} + +static Kernel::Void NE_PCISetCfgTarget(Kernel::UInt bar, Kernel::UShort bus, Kernel::UShort dev, + Kernel::UShort fun) { + Kernel::UInt target = 0x80000000 | ((Kernel::UInt) bus << 16) | ((Kernel::UInt) dev << 11) | + ((Kernel::UInt) fun << 8) | (bar & 0xFC); + + Kernel::HAL::rt_out32((Kernel::UShort) Kernel::PCI::PciConfigKind::ConfigAddress, target); + + Kernel::HAL::rt_wait_400ns(); +} + +namespace Kernel::PCI { +Device::Device(UShort bus, UShort device, UShort func, UInt32 bar) + : fBus(bus), fDevice(device), fFunction(func), fBar(bar) {} + +Device::~Device() = default; + +UInt Device::Read(UInt bar, Size sz) { + // Ensure aligned access by masking to 4-byte boundary + NE_PCISetCfgTarget(bar & 0xFC, fBus, fDevice, fFunction); + + // Read 4 bytes and shift out the correct value + UInt data = HAL::rt_in32((UShort) PciConfigKind::ConfigData); + + if (sz == 4) return data; + if (sz == 2) return (data >> ((bar & 2) * 8)) & 0xFFFF; + if (sz == 1) return (data >> ((bar & 3) * 8)) & 0xFF; + + return (UShort) PciConfigKind::Invalid; +} + +void Device::Write(UInt bar, UIntPtr data, Size sz) { + NE_PCISetCfgTarget(bar & 0xFC, fBus, fDevice, fFunction); + + if (sz == 4) { + HAL::rt_out32((UShort) PciConfigKind::ConfigAddress, (UInt) data); + } else if (sz == 2) { + UInt temp = HAL::rt_in32((UShort) PciConfigKind::ConfigData); + + temp &= ~(0xFFFF << ((bar & 2) * 8)); + temp |= (data & 0xFFFF) << ((bar & 2) * 8); + + HAL::rt_out32((UShort) PciConfigKind::ConfigAddress, temp); + } else if (sz == 1) { + UInt temp = HAL::rt_in32((UShort) PciConfigKind::ConfigData); + + temp &= ~(0xFF << ((bar & 3) * 8)); + temp |= (data & 0xFF) << ((bar & 3) * 8); + + HAL::rt_out32((UShort) PciConfigKind::ConfigAddress, temp); + } +} + +UShort Device::DeviceId() { + return (UShort) (NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) >> 16); +} + +UShort Device::VendorId() { + return (UShort) (NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) & 0xFFFF); +} + +UShort Device::InterfaceId() { + return (UShort) (NE_PCIReadRaw(0x09, fBus, fDevice, fFunction) >> 16); +} + +UChar Device::Class() { + return (UChar) (NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 24); +} + +UChar Device::Subclass() { + return (UChar) (NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 16); +} + +UChar Device::ProgIf() { + return (UChar) (NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 8); +} + +UChar Device::HeaderType() { + return (UChar) (NE_PCIReadRaw(0xC, fBus, fDevice, fFunction) >> 16); +} + +void Device::EnableMmio() { + UInt32 command = Read(0x04, sizeof(UInt32)); + command |= (1 << 1); // Memory Space Enable (bit 1) + + Write(0x04, command, sizeof(UInt32)); +} + +void Device::BecomeBusMaster() { + UInt32 command = Read(0x04, sizeof(UInt32)); + command |= (1 << 2); // Bus Master Enable (bit 2) + Write(0x04, command, sizeof(UInt32)); +} + +UIntPtr Device::Bar(UInt32 bar_in) { + UInt32 bar = NE_PCIReadRaw(bar_in, fBus, fDevice, fFunction); + + if (bar & PCI_BAR_IO) return static_cast(bar & ~0x03); + + if (bar & PCI_BAR_64) { + UInt32 high = NE_PCIReadRaw((bar_in + 4) & ~0x03, fBus, fDevice, fFunction); + return (static_cast(high) << 32) | (bar & ~0x0F); + } + + return static_cast(bar & ~0x0F); +} + +UShort Device::Vendor() { + UShort vendor = this->VendorId(); + return vendor; +} + +Device::operator bool() { + return this->VendorId() != (UShort) PciConfigKind::Invalid; +} +} // namespace Kernel::PCI diff --git a/src/kernel/HALKit/AMD64/PCI/Express.cc b/src/kernel/HALKit/AMD64/PCI/Express.cc deleted file mode 100644 index e0264d9e..00000000 --- a/src/kernel/HALKit/AMD64/PCI/Express.cc +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -namespace Kernel {} diff --git a/src/kernel/HALKit/AMD64/PCI/Express.cpp b/src/kernel/HALKit/AMD64/PCI/Express.cpp new file mode 100644 index 00000000..e0264d9e --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/Express.cpp @@ -0,0 +1,7 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +namespace Kernel {} diff --git a/src/kernel/HALKit/AMD64/PCI/IO.cc b/src/kernel/HALKit/AMD64/PCI/IO.cc deleted file mode 100644 index 8cc9c83a..00000000 --- a/src/kernel/HALKit/AMD64/PCI/IO.cc +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include diff --git a/src/kernel/HALKit/AMD64/PCI/IO.cpp b/src/kernel/HALKit/AMD64/PCI/IO.cpp new file mode 100644 index 00000000..8cc9c83a --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/IO.cpp @@ -0,0 +1,5 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include diff --git a/src/kernel/HALKit/AMD64/PCI/Iterator.cc b/src/kernel/HALKit/AMD64/PCI/Iterator.cc deleted file mode 100644 index 8216befa..00000000 --- a/src/kernel/HALKit/AMD64/PCI/Iterator.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -namespace Kernel::PCI { -Iterator::Iterator(const Types::PciDeviceKind type, UInt32 bar) { - // probe devices. - for (Int32 bus = 0; bus < NE_BUS_COUNT; ++bus) { - for (Int32 device = 0; device < NE_DEVICE_COUNT; ++device) { - for (Int32 function = 0; function < NE_FUNCTION_COUNT; ++function) { - Device dev(bus, device, function, bar); - - if (dev.Class() == type) { - fDevices[bus] = dev; - } - } - } - } -} - -Iterator::~Iterator() {} - -Ref Iterator::operator[](const Size& at) { - return fDevices[at]; -} -} // namespace Kernel::PCI diff --git a/src/kernel/HALKit/AMD64/PCI/Iterator.cpp b/src/kernel/HALKit/AMD64/PCI/Iterator.cpp new file mode 100644 index 00000000..8216befa --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/Iterator.cpp @@ -0,0 +1,28 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +namespace Kernel::PCI { +Iterator::Iterator(const Types::PciDeviceKind type, UInt32 bar) { + // probe devices. + for (Int32 bus = 0; bus < NE_BUS_COUNT; ++bus) { + for (Int32 device = 0; device < NE_DEVICE_COUNT; ++device) { + for (Int32 function = 0; function < NE_FUNCTION_COUNT; ++function) { + Device dev(bus, device, function, bar); + + if (dev.Class() == type) { + fDevices[bus] = dev; + } + } + } + } +} + +Iterator::~Iterator() {} + +Ref Iterator::operator[](const Size& at) { + return fDevices[at]; +} +} // namespace Kernel::PCI diff --git a/src/kernel/HALKit/AMD64/PCI/PCI.cc b/src/kernel/HALKit/AMD64/PCI/PCI.cc deleted file mode 100644 index b8a1302d..00000000 --- a/src/kernel/HALKit/AMD64/PCI/PCI.cc +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include diff --git a/src/kernel/HALKit/AMD64/PCI/PCI.cpp b/src/kernel/HALKit/AMD64/PCI/PCI.cpp new file mode 100644 index 00000000..b8a1302d --- /dev/null +++ b/src/kernel/HALKit/AMD64/PCI/PCI.cpp @@ -0,0 +1,5 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include diff --git a/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc deleted file mode 100644 index 456b6a2a..00000000 --- a/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kSATAErrTaskFile (1 << 30) -#define kSATAPxCmdST (0x0001) -#define kSATAPxCmdFre (0x0010) -#define kSATAPxCmdFR (0x4000) -#define kSATAPxCmdCR (0x8000) - -#define kSATALBAMode (1 << 6) - -#define kSATASRBsy (0x80) -#define kSATASRDrq (0x08) - -#define kSATABohcBiosOwned (1 << 0) -#define kSATABohcOSOwned (1 << 1) - -#define kSATAPortCnt (0x20) - -#define kSATASig (0x00000101) -#define kSATAPISig (0xEB140101) - -#define kSATAProgIfAHCI (0x01) -#define kSATASubClass (0x06) -#define kSATABar5 (0x24) - -using namespace Kernel; - -STATIC PCI::Device kSATADev; -STATIC HbaMemRef kSATAHba; -STATIC Lba kSATASectorCount = 0UL; -STATIC UInt16 kSATAIndex = 0U; -STATIC Char kCurrentDiskModel[50] = {"GENERIC SATA"}; -STATIC UInt16 kSATAPortsImplemented = 0U; -STATIC ALIGN(kib_cast(4)) UInt8 kIdentifyData[kAHCISectorSize] = {0}; - -template -STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz, - SizeT size_buffer); - -STATIC Int32 drv_find_cmd_slot_ahci(HbaPort* port); - -STATIC Void drv_compute_disk_ahci(); - -STATIC SizeT drv_get_size_ahci(); - -STATIC SizeT drv_get_sector_count_ahci(); - -/***********************************************************************************/ -/// @brief Identify device and read LBA info, Disk OEM vendor. -/***********************************************************************************/ -STATIC Void drv_compute_disk_ahci() { - kSATASectorCount = 0UL; - - rt_set_memory(kIdentifyData, 0, kAHCISectorSize); - - drv_std_input_output_ahci(0, kIdentifyData, kAHCISectorSize, kAHCISectorSize); - - // --> Reinterpret the 512-byte buffer as an array of 256 UInt16 words - UInt16* identify_words = reinterpret_cast(kIdentifyData); - - /// Extract 48-bit LBA. - UInt64 lba48_sectors = 0UL; - lba48_sectors |= (UInt64) identify_words[100]; - lba48_sectors |= (UInt64) identify_words[101] << 16; - lba48_sectors |= (UInt64) identify_words[102] << 32; - - if (lba48_sectors == 0) - kSATASectorCount = (identify_words[61] << 16) | identify_words[60]; - else - kSATASectorCount = lba48_sectors; - - for (Int32 i = 0; i < 20; i++) { - kCurrentDiskModel[i * 2] = (identify_words[27 + i] >> 8) & 0xFF; - kCurrentDiskModel[i * 2 + 1] = identify_words[27 + i] & 0xFF; - } - - kCurrentDiskModel[40] = '\0'; - - (Void)(kout << "SATA Sector Count: " << hex_number(kSATASectorCount) << kendl); - (Void)(kout << "SATA Disk Model: " << kCurrentDiskModel << kendl); -} - -/***********************************************************************************/ -/// @brief Finds a command slot for a HBA port. -/// @param port The port to search on. -/// @return The slot, or -1. -/***********************************************************************************/ -STATIC Int32 drv_find_cmd_slot_ahci(HbaPort* port) { - UInt32 slots = port->Sact | port->Ci; - - for (Int32 i = 0; i < kSATAPortCnt; ++i) // AHCI supports up to 32 slots - { - if ((slots & (1U << i)) == 0) return i; - } - - return -1; // no free slot found -} - -/***********************************************************************************/ -/// @brief Send an AHCI command, according to the template parameters. -/// @param lba Logical Block Address to look for. -/// @param buffer The data buffer to transfer. -/// @param sector_sz The disk's sector size (unused) -/// @param size_buffer The size of the **buffer** parameter. -/***********************************************************************************/ -template -STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz, - SizeT size_buffer) { - if (sector_sz == 0) { - kout << "ahci: Invalid sector size.\r"; - err_global_get() = kErrorDisk; - return; - } - - lba /= sector_sz; - - if (!buffer || size_buffer == 0) { - kout << "ahci: Invalid buffer for AHCI I/O.\r"; - err_global_get() = kErrorDisk; - return; - } - - UIntPtr slot = drv_find_cmd_slot_ahci(&kSATAHba->Ports[kSATAIndex]); - - UInt16 timeout = 0; - - constexpr static UInt16 kTimeout = 0x8000; - - while (slot == ~0UL) { - if (timeout > kTimeout) { - kout << "ahci: No free command slot found, AHCI disk is busy!\r"; - - err_global_get() = kErrorDisk; - return; - } - - slot = drv_find_cmd_slot_ahci(&kSATAHba->Ports[kSATAIndex]); - ++timeout; - } - - volatile HbaCmdHeader* command_header = - (volatile HbaCmdHeader*) ((UInt64) kSATAHba->Ports[kSATAIndex].Clb); - - command_header += slot; - - MUST_PASS(command_header); - - // Clear old command table memory - volatile HbaCmdTbl* command_table = - (volatile HbaCmdTbl*) (((UInt64) command_header->Ctbau << 32) | command_header->Ctba); - - MUST_PASS(command_table); - - rt_set_memory((VoidPtr) command_table, 0, sizeof(HbaCmdTbl)); - - VoidPtr ptr = rtl_dma_alloc(size_buffer, kib_cast(4)); - - rtl_dma_flush(ptr, size_buffer); - - if (Write) { - rt_copy_memory(buffer, ptr, size_buffer); - } - - rtl_dma_flush(ptr, size_buffer); - - // Build the PRD table. - SizeT bytes_remaining = size_buffer; - SizeT prdt_index = 0; - UIntPtr buffer_phys = (UIntPtr) ptr; - - while (bytes_remaining > 0) { - SizeT chunk_size = bytes_remaining; - - if (chunk_size > kib_cast(32)) chunk_size = kib_cast(32); - - command_table->Prdt[prdt_index].Dba = (UInt32) (buffer_phys & 0xFFFFFFFF); - command_table->Prdt[prdt_index].Dbau = (UInt32) (buffer_phys >> 32); - command_table->Prdt[prdt_index].Dbc = (UInt32) (chunk_size - 1); - command_table->Prdt[prdt_index].Ie = NO; - - buffer_phys += chunk_size; - bytes_remaining -= chunk_size; - - ++prdt_index; - } - - // Mark the last PRD entry, for the FIS to process the table. - command_table->Prdt[prdt_index - 1].Ie = YES; - - if (bytes_remaining > 0) { - kout << "ahci: AHCI PRDT overflow, cannot map full buffer.\r"; - err_global_get() = kErrorDisk; - rtl_dma_free(size_buffer); - - return; - } - - command_header->Prdtl = prdt_index; - command_header->HbaFlags.Struct.Cfl = sizeof(FisRegH2D) / sizeof(UInt32); - command_header->HbaFlags.Struct.Write = Write; - - volatile FisRegH2D* h2d_fis = (volatile FisRegH2D*) (&command_table->Cfis[0]); - - h2d_fis->FisType = kFISTypeRegH2D; - h2d_fis->CmdOrCtrl = CommandOrCTRL; - h2d_fis->Command = - (Identify ? kAHCICmdIdentify : (Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx)); - - h2d_fis->Lba0 = (lba >> 0) & 0xFF; - h2d_fis->Lba1 = (lba >> 8) & 0xFF; - h2d_fis->Lba2 = (lba >> 16) & 0xFF; - h2d_fis->Lba3 = (lba >> 24) & 0xFF; - h2d_fis->Lba4 = (lba >> 32) & 0xFF; - h2d_fis->Lba5 = (lba >> 40) & 0xFF; - - h2d_fis->Device = 0; - - if (Identify) { - h2d_fis->CountLow = 1; - h2d_fis->CountHigh = 0; - } else { - h2d_fis->Device = kSATALBAMode; - h2d_fis->CountLow = (size_buffer / kAHCISectorSize) & 0xFF; - h2d_fis->CountHigh = ((size_buffer / kAHCISectorSize) >> 8) & 0xFF; - } - - rtl_dma_flush(ptr, size_buffer); - - // Issue command - kSATAHba->Ports[kSATAIndex].Ci = (1 << slot); - - timeout = 0UL; - - while (YES) { - if (timeout > kTimeout) { - kout << "ahci: disk-hangup, corrupted-disk.\r"; - err_global_get() = kErrorDiskIsCorrupted; - rtl_dma_free(size_buffer); - - return; - } - - ++timeout; - - if (!(kSATAHba->Ports[kSATAIndex].Ci & (1 << slot))) break; - } - - rtl_dma_flush(ptr, size_buffer); - - if (kSATAHba->Is & kSATAErrTaskFile) { - kout << "ahci: tf-error when doing I/O.\r"; - - rtl_dma_free(size_buffer); - err_global_get() = kErrorDiskIsCorrupted; - - return; - } else { - if (!Write) { - rtl_dma_flush(ptr, size_buffer); - rt_copy_memory(ptr, buffer, size_buffer); - rtl_dma_flush(ptr, size_buffer); - } - - if ((kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)) == 0) { - goto ahci_io_end; - } else { - kout << "ahci: Disk still busy after command completion!\r"; - while (kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)); - } - - ahci_io_end: - rtl_dma_free(size_buffer); - err_global_get() = kErrorSuccess; - } -} - -/*** - @brief Gets the number of sectors inside the drive. - @return Sector size in bytes. - */ -STATIC ATTRIBUTE(unused) -SizeT drv_get_sector_count_ahci() { - return kSATASectorCount; -} - -/// @brief Get the drive size. -/// @return Disk size in bytes. -STATIC ATTRIBUTE(unused) -SizeT drv_get_size_ahci() { - return drv_std_get_sector_count() * kAHCISectorSize; -} - -/// @brief Enable Host and probe using the IDENTIFY command. -STATIC BOOL ahci_enable_and_probe() { - if (kSATAHba->Cap == 0x0) return NO; - - kSATAHba->Ports[kSATAIndex].Cmd &= ~kSATAPxCmdFre; - kSATAHba->Ports[kSATAIndex].Cmd &= ~kSATAPxCmdST; - - while (YES) { - if (kSATAHba->Ports[kSATAIndex].Cmd & kSATAPxCmdCR) continue; - - if (kSATAHba->Ports[kSATAIndex].Cmd & kSATAPxCmdFR) continue; - - break; - } - - // Now we are ready. - - kSATAHba->Ports[kSATAIndex].Cmd |= kSATAPxCmdFre; - kSATAHba->Ports[kSATAIndex].Cmd |= kSATAPxCmdST; - - if (kSATAHba->Bohc & kSATABohcBiosOwned) { - kSATAHba->Bohc |= kSATABohcOSOwned; - - while (kSATAHba->Bohc & kSATABohcBiosOwned) { - ; - } - } - - drv_compute_disk_ahci(); - - return YES; -} - -STATIC Bool drv_init_command_structures_ahci() { - // Allocate 4KiB for Command List (32 headers) - VoidPtr clb_mem = rtl_dma_alloc(4096, 1024); - if (!clb_mem) { - kout << "Failed to allocate CLB memory!\r"; - return NO; - } - - UIntPtr clb_phys = HAL::mm_get_page_addr(clb_mem); - - kSATAHba->Ports[kSATAIndex].Clb = (UInt32) (clb_phys & 0xFFFFFFFF); - kSATAHba->Ports[kSATAIndex].Clbu = (UInt32) (clb_phys >> 32); - - // Clear it - rt_set_memory(clb_mem, 0, kib_cast(4)); - - // For each command slot (up to 32) - volatile HbaCmdHeader* header = (volatile HbaCmdHeader*) clb_mem; - - for (Int32 i = 0; i < 32; ++i) { - // Allocate 4KiB for Command Table - VoidPtr ct_mem = rtl_dma_alloc(4096, 128); - if (!ct_mem) { - (Void)(kout << "Failed to allocate CTB memory for slot " << hex_number(i)); - kout << "!\r"; - return NO; - } - - UIntPtr ct_phys = HAL::mm_get_page_addr(ct_mem); - - header[i].Ctba = (UInt32) (ct_phys & 0xFFFFFFFF); - header[i].Ctbau = (UInt32) (ct_phys >> 32); - - // Clear the command table - rt_set_memory((VoidPtr) ct_mem, 0, 4096); - } - - return YES; -} - -/// @brief Initializes an AHCI disk. -/// @param pi the amount of ports that have been detected. -/// @param atapi reference value, tells whether we should detect ATAPI instead of SATA. -/// @return if the disk was successfully initialized or not. -STATIC Bool drv_std_init_ahci(UInt16& pi, BOOL& atapi) { - /// TODO: Iterator is good enough, but we need to expand it. - PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController, 0x00); - - for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) { - kSATADev = iterator[device_index].Leak(); // Leak device. - - if (kSATADev.Subclass() == kSATASubClass && kSATADev.ProgIf() == kSATAProgIfAHCI) { - kSATADev.EnableMmio(); - kSATADev.BecomeBusMaster(); - - HbaMem* mem_ahci = (HbaMem*) kSATADev.Bar(kSATABar5); - - HAL::mm_map_page( - (VoidPtr) mem_ahci, (VoidPtr) mem_ahci, - HAL::kMMFlagsPresent | HAL::kMMFlagsWr | HAL::kMMFlagsPCD | HAL::kMMFlagsPwt); - - UInt32 ports_implemented = mem_ahci->Pi; - UInt16 ahci_index = 0; - - pi = ports_implemented; - - const UInt16 kSATAMaxPortsImplemented = ports_implemented; - const UInt32 kSATASignature = kSATASig; - const UInt32 kSATAPISignature = kSATAPISig; - const UInt8 kSATAPresent = 0x03; - const UInt8 kSATAIPMActive = 0x01; - - if (kSATAMaxPortsImplemented < 1) continue; - - while (ports_implemented) { - UInt8 ipm = (mem_ahci->Ports[ahci_index].Ssts >> 8) & 0x0F; - UInt8 det = (mem_ahci->Ports[ahci_index].Ssts & 0x0F); - - if (det != kSATAPresent || ipm != kSATAIPMActive) continue; - - if ((mem_ahci->Ports[ahci_index].Sig == kSATASignature) || - (atapi && kSATAPISignature == mem_ahci->Ports[ahci_index].Sig)) { - kSATAIndex = ahci_index; - kSATAHba = mem_ahci; - - if (!drv_init_command_structures_ahci()) { - err_global_get() = kErrorDisk; - } - - goto success_hba_fetch; - } - - ports_implemented >>= 1; - ++ahci_index; - } - } - } - - err_global_get() = kErrorDisk; - - return NO; - -success_hba_fetch: - if (ahci_enable_and_probe()) { - err_global_get() = kErrorSuccess; - } - - return err_global_get() == kErrorSuccess; -} - -/// @brief Checks if an AHCI device is detected. -/// @return Either if detected, or not found. -Bool drv_std_detected_ahci() { - return kSATADev.DeviceId() != (UShort) PCI::PciConfigKind::Invalid && - kSATADev.Bar(kSATABar5) != 0; -} - -// ================================================================================================ - -// -/// @note This applies only if we compile with AHCI as a default disk driver. -// - -// ================================================================================================ - -#ifdef __AHCI__ - -//////////////////////////////////////////////////// -/// -//////////////////////////////////////////////////// -Void drv_std_write(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) { - drv_std_input_output_ahci(lba, reinterpret_cast(buffer), sector_sz, - size_buffer); -} - -//////////////////////////////////////////////////// -/// -//////////////////////////////////////////////////// -Void drv_std_read(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) { - drv_std_input_output_ahci(lba, reinterpret_cast(buffer), sector_sz, - size_buffer); -} - -//////////////////////////////////////////////////// -/// -//////////////////////////////////////////////////// -Bool drv_std_init(UInt16& pi) { - BOOL atapi = NO; - return drv_std_init_ahci(pi, atapi); -} - -//////////////////////////////////////////////////// -/// -//////////////////////////////////////////////////// -Bool drv_std_detected(Void) { - return drv_std_detected_ahci(); -} - -//////////////////////////////////////////////////// -/** - @brief Gets the number of sectors inside the drive. - @return Sector size in bytes. - */ -//////////////////////////////////////////////////// -SizeT drv_std_get_sector_count() { - return drv_get_sector_count_ahci(); -} - -//////////////////////////////////////////////////// -/// @brief Get the drive size. -/// @return Disk size in bytes. -//////////////////////////////////////////////////// -SizeT drv_std_get_size() { - return drv_get_size_ahci(); -} - -#endif // ifdef __AHCI__ - -namespace Kernel { -/// @brief Initialize an AHCI device (StorageKit) -UInt16 sk_init_ahci_device(BOOL atapi) { - UInt16 pi = 0; - - if (drv_std_init_ahci(pi, atapi)) kSATAPortsImplemented = pi; - - return pi; -} - -/// @brief Implementation details namespace. -namespace Detail { - /// @brief Read AHCI device. - /// @param self device - /// @param mnt mounted disk. - STATIC Void sk_io_read_ahci(IDevice* self, IMountpoint* mnt) { - AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; - - err_global_get() = kErrorDisk; - - if (!dev) return; - - auto disk = mnt->GetAddressOf(dev->GetIndex()); - - if (!disk) return; - - err_global_get() = kErrorSuccess; - - drv_std_input_output_ahci(disk->fPacket.fPacketLba / kAHCISectorSize, - (UInt8*) disk->fPacket.fPacketContent, kAHCISectorSize, - disk->fPacket.fPacketSize); - } - - /// @brief Write AHCI device. - /// @param self device - /// @param mnt mounted disk. - STATIC Void sk_io_write_ahci(IDevice* self, IMountpoint* mnt) { - AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; - - err_global_get() = kErrorDisk; - - if (!dev) return; - - auto disk = mnt->GetAddressOf(dev->GetIndex()); - - if (!disk) return; - - err_global_get() = kErrorSuccess; - - drv_std_input_output_ahci(disk->fPacket.fPacketLba / kAHCISectorSize, - (UInt8*) disk->fPacket.fPacketContent, kAHCISectorSize, - disk->fPacket.fPacketSize); - } -} // namespace Detail - -/// @brief Acquires a new AHCI device with drv_index in mind. -/// @param drv_index The drive index to assign. -/// @return A wrapped device interface if successful, or error code. -ErrorOr sk_acquire_ahci_device(UInt32 drv_index) { - if (!drv_std_detected_ahci()) return ErrorOr(kErrorDisk); - - AHCIDeviceInterface device(Detail::sk_io_read_ahci, Detail::sk_io_write_ahci); - - device.SetPortsImplemented(kSATAPortsImplemented); - device.SetIndex(drv_index); - - return ErrorOr(device); -} -} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cpp b/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cpp new file mode 100644 index 00000000..456b6a2a --- /dev/null +++ b/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cpp @@ -0,0 +1,588 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kSATAErrTaskFile (1 << 30) +#define kSATAPxCmdST (0x0001) +#define kSATAPxCmdFre (0x0010) +#define kSATAPxCmdFR (0x4000) +#define kSATAPxCmdCR (0x8000) + +#define kSATALBAMode (1 << 6) + +#define kSATASRBsy (0x80) +#define kSATASRDrq (0x08) + +#define kSATABohcBiosOwned (1 << 0) +#define kSATABohcOSOwned (1 << 1) + +#define kSATAPortCnt (0x20) + +#define kSATASig (0x00000101) +#define kSATAPISig (0xEB140101) + +#define kSATAProgIfAHCI (0x01) +#define kSATASubClass (0x06) +#define kSATABar5 (0x24) + +using namespace Kernel; + +STATIC PCI::Device kSATADev; +STATIC HbaMemRef kSATAHba; +STATIC Lba kSATASectorCount = 0UL; +STATIC UInt16 kSATAIndex = 0U; +STATIC Char kCurrentDiskModel[50] = {"GENERIC SATA"}; +STATIC UInt16 kSATAPortsImplemented = 0U; +STATIC ALIGN(kib_cast(4)) UInt8 kIdentifyData[kAHCISectorSize] = {0}; + +template +STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz, + SizeT size_buffer); + +STATIC Int32 drv_find_cmd_slot_ahci(HbaPort* port); + +STATIC Void drv_compute_disk_ahci(); + +STATIC SizeT drv_get_size_ahci(); + +STATIC SizeT drv_get_sector_count_ahci(); + +/***********************************************************************************/ +/// @brief Identify device and read LBA info, Disk OEM vendor. +/***********************************************************************************/ +STATIC Void drv_compute_disk_ahci() { + kSATASectorCount = 0UL; + + rt_set_memory(kIdentifyData, 0, kAHCISectorSize); + + drv_std_input_output_ahci(0, kIdentifyData, kAHCISectorSize, kAHCISectorSize); + + // --> Reinterpret the 512-byte buffer as an array of 256 UInt16 words + UInt16* identify_words = reinterpret_cast(kIdentifyData); + + /// Extract 48-bit LBA. + UInt64 lba48_sectors = 0UL; + lba48_sectors |= (UInt64) identify_words[100]; + lba48_sectors |= (UInt64) identify_words[101] << 16; + lba48_sectors |= (UInt64) identify_words[102] << 32; + + if (lba48_sectors == 0) + kSATASectorCount = (identify_words[61] << 16) | identify_words[60]; + else + kSATASectorCount = lba48_sectors; + + for (Int32 i = 0; i < 20; i++) { + kCurrentDiskModel[i * 2] = (identify_words[27 + i] >> 8) & 0xFF; + kCurrentDiskModel[i * 2 + 1] = identify_words[27 + i] & 0xFF; + } + + kCurrentDiskModel[40] = '\0'; + + (Void)(kout << "SATA Sector Count: " << hex_number(kSATASectorCount) << kendl); + (Void)(kout << "SATA Disk Model: " << kCurrentDiskModel << kendl); +} + +/***********************************************************************************/ +/// @brief Finds a command slot for a HBA port. +/// @param port The port to search on. +/// @return The slot, or -1. +/***********************************************************************************/ +STATIC Int32 drv_find_cmd_slot_ahci(HbaPort* port) { + UInt32 slots = port->Sact | port->Ci; + + for (Int32 i = 0; i < kSATAPortCnt; ++i) // AHCI supports up to 32 slots + { + if ((slots & (1U << i)) == 0) return i; + } + + return -1; // no free slot found +} + +/***********************************************************************************/ +/// @brief Send an AHCI command, according to the template parameters. +/// @param lba Logical Block Address to look for. +/// @param buffer The data buffer to transfer. +/// @param sector_sz The disk's sector size (unused) +/// @param size_buffer The size of the **buffer** parameter. +/***********************************************************************************/ +template +STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz, + SizeT size_buffer) { + if (sector_sz == 0) { + kout << "ahci: Invalid sector size.\r"; + err_global_get() = kErrorDisk; + return; + } + + lba /= sector_sz; + + if (!buffer || size_buffer == 0) { + kout << "ahci: Invalid buffer for AHCI I/O.\r"; + err_global_get() = kErrorDisk; + return; + } + + UIntPtr slot = drv_find_cmd_slot_ahci(&kSATAHba->Ports[kSATAIndex]); + + UInt16 timeout = 0; + + constexpr static UInt16 kTimeout = 0x8000; + + while (slot == ~0UL) { + if (timeout > kTimeout) { + kout << "ahci: No free command slot found, AHCI disk is busy!\r"; + + err_global_get() = kErrorDisk; + return; + } + + slot = drv_find_cmd_slot_ahci(&kSATAHba->Ports[kSATAIndex]); + ++timeout; + } + + volatile HbaCmdHeader* command_header = + (volatile HbaCmdHeader*) ((UInt64) kSATAHba->Ports[kSATAIndex].Clb); + + command_header += slot; + + MUST_PASS(command_header); + + // Clear old command table memory + volatile HbaCmdTbl* command_table = + (volatile HbaCmdTbl*) (((UInt64) command_header->Ctbau << 32) | command_header->Ctba); + + MUST_PASS(command_table); + + rt_set_memory((VoidPtr) command_table, 0, sizeof(HbaCmdTbl)); + + VoidPtr ptr = rtl_dma_alloc(size_buffer, kib_cast(4)); + + rtl_dma_flush(ptr, size_buffer); + + if (Write) { + rt_copy_memory(buffer, ptr, size_buffer); + } + + rtl_dma_flush(ptr, size_buffer); + + // Build the PRD table. + SizeT bytes_remaining = size_buffer; + SizeT prdt_index = 0; + UIntPtr buffer_phys = (UIntPtr) ptr; + + while (bytes_remaining > 0) { + SizeT chunk_size = bytes_remaining; + + if (chunk_size > kib_cast(32)) chunk_size = kib_cast(32); + + command_table->Prdt[prdt_index].Dba = (UInt32) (buffer_phys & 0xFFFFFFFF); + command_table->Prdt[prdt_index].Dbau = (UInt32) (buffer_phys >> 32); + command_table->Prdt[prdt_index].Dbc = (UInt32) (chunk_size - 1); + command_table->Prdt[prdt_index].Ie = NO; + + buffer_phys += chunk_size; + bytes_remaining -= chunk_size; + + ++prdt_index; + } + + // Mark the last PRD entry, for the FIS to process the table. + command_table->Prdt[prdt_index - 1].Ie = YES; + + if (bytes_remaining > 0) { + kout << "ahci: AHCI PRDT overflow, cannot map full buffer.\r"; + err_global_get() = kErrorDisk; + rtl_dma_free(size_buffer); + + return; + } + + command_header->Prdtl = prdt_index; + command_header->HbaFlags.Struct.Cfl = sizeof(FisRegH2D) / sizeof(UInt32); + command_header->HbaFlags.Struct.Write = Write; + + volatile FisRegH2D* h2d_fis = (volatile FisRegH2D*) (&command_table->Cfis[0]); + + h2d_fis->FisType = kFISTypeRegH2D; + h2d_fis->CmdOrCtrl = CommandOrCTRL; + h2d_fis->Command = + (Identify ? kAHCICmdIdentify : (Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx)); + + h2d_fis->Lba0 = (lba >> 0) & 0xFF; + h2d_fis->Lba1 = (lba >> 8) & 0xFF; + h2d_fis->Lba2 = (lba >> 16) & 0xFF; + h2d_fis->Lba3 = (lba >> 24) & 0xFF; + h2d_fis->Lba4 = (lba >> 32) & 0xFF; + h2d_fis->Lba5 = (lba >> 40) & 0xFF; + + h2d_fis->Device = 0; + + if (Identify) { + h2d_fis->CountLow = 1; + h2d_fis->CountHigh = 0; + } else { + h2d_fis->Device = kSATALBAMode; + h2d_fis->CountLow = (size_buffer / kAHCISectorSize) & 0xFF; + h2d_fis->CountHigh = ((size_buffer / kAHCISectorSize) >> 8) & 0xFF; + } + + rtl_dma_flush(ptr, size_buffer); + + // Issue command + kSATAHba->Ports[kSATAIndex].Ci = (1 << slot); + + timeout = 0UL; + + while (YES) { + if (timeout > kTimeout) { + kout << "ahci: disk-hangup, corrupted-disk.\r"; + err_global_get() = kErrorDiskIsCorrupted; + rtl_dma_free(size_buffer); + + return; + } + + ++timeout; + + if (!(kSATAHba->Ports[kSATAIndex].Ci & (1 << slot))) break; + } + + rtl_dma_flush(ptr, size_buffer); + + if (kSATAHba->Is & kSATAErrTaskFile) { + kout << "ahci: tf-error when doing I/O.\r"; + + rtl_dma_free(size_buffer); + err_global_get() = kErrorDiskIsCorrupted; + + return; + } else { + if (!Write) { + rtl_dma_flush(ptr, size_buffer); + rt_copy_memory(ptr, buffer, size_buffer); + rtl_dma_flush(ptr, size_buffer); + } + + if ((kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)) == 0) { + goto ahci_io_end; + } else { + kout << "ahci: Disk still busy after command completion!\r"; + while (kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)); + } + + ahci_io_end: + rtl_dma_free(size_buffer); + err_global_get() = kErrorSuccess; + } +} + +/*** + @brief Gets the number of sectors inside the drive. + @return Sector size in bytes. + */ +STATIC ATTRIBUTE(unused) +SizeT drv_get_sector_count_ahci() { + return kSATASectorCount; +} + +/// @brief Get the drive size. +/// @return Disk size in bytes. +STATIC ATTRIBUTE(unused) +SizeT drv_get_size_ahci() { + return drv_std_get_sector_count() * kAHCISectorSize; +} + +/// @brief Enable Host and probe using the IDENTIFY command. +STATIC BOOL ahci_enable_and_probe() { + if (kSATAHba->Cap == 0x0) return NO; + + kSATAHba->Ports[kSATAIndex].Cmd &= ~kSATAPxCmdFre; + kSATAHba->Ports[kSATAIndex].Cmd &= ~kSATAPxCmdST; + + while (YES) { + if (kSATAHba->Ports[kSATAIndex].Cmd & kSATAPxCmdCR) continue; + + if (kSATAHba->Ports[kSATAIndex].Cmd & kSATAPxCmdFR) continue; + + break; + } + + // Now we are ready. + + kSATAHba->Ports[kSATAIndex].Cmd |= kSATAPxCmdFre; + kSATAHba->Ports[kSATAIndex].Cmd |= kSATAPxCmdST; + + if (kSATAHba->Bohc & kSATABohcBiosOwned) { + kSATAHba->Bohc |= kSATABohcOSOwned; + + while (kSATAHba->Bohc & kSATABohcBiosOwned) { + ; + } + } + + drv_compute_disk_ahci(); + + return YES; +} + +STATIC Bool drv_init_command_structures_ahci() { + // Allocate 4KiB for Command List (32 headers) + VoidPtr clb_mem = rtl_dma_alloc(4096, 1024); + if (!clb_mem) { + kout << "Failed to allocate CLB memory!\r"; + return NO; + } + + UIntPtr clb_phys = HAL::mm_get_page_addr(clb_mem); + + kSATAHba->Ports[kSATAIndex].Clb = (UInt32) (clb_phys & 0xFFFFFFFF); + kSATAHba->Ports[kSATAIndex].Clbu = (UInt32) (clb_phys >> 32); + + // Clear it + rt_set_memory(clb_mem, 0, kib_cast(4)); + + // For each command slot (up to 32) + volatile HbaCmdHeader* header = (volatile HbaCmdHeader*) clb_mem; + + for (Int32 i = 0; i < 32; ++i) { + // Allocate 4KiB for Command Table + VoidPtr ct_mem = rtl_dma_alloc(4096, 128); + if (!ct_mem) { + (Void)(kout << "Failed to allocate CTB memory for slot " << hex_number(i)); + kout << "!\r"; + return NO; + } + + UIntPtr ct_phys = HAL::mm_get_page_addr(ct_mem); + + header[i].Ctba = (UInt32) (ct_phys & 0xFFFFFFFF); + header[i].Ctbau = (UInt32) (ct_phys >> 32); + + // Clear the command table + rt_set_memory((VoidPtr) ct_mem, 0, 4096); + } + + return YES; +} + +/// @brief Initializes an AHCI disk. +/// @param pi the amount of ports that have been detected. +/// @param atapi reference value, tells whether we should detect ATAPI instead of SATA. +/// @return if the disk was successfully initialized or not. +STATIC Bool drv_std_init_ahci(UInt16& pi, BOOL& atapi) { + /// TODO: Iterator is good enough, but we need to expand it. + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController, 0x00); + + for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) { + kSATADev = iterator[device_index].Leak(); // Leak device. + + if (kSATADev.Subclass() == kSATASubClass && kSATADev.ProgIf() == kSATAProgIfAHCI) { + kSATADev.EnableMmio(); + kSATADev.BecomeBusMaster(); + + HbaMem* mem_ahci = (HbaMem*) kSATADev.Bar(kSATABar5); + + HAL::mm_map_page( + (VoidPtr) mem_ahci, (VoidPtr) mem_ahci, + HAL::kMMFlagsPresent | HAL::kMMFlagsWr | HAL::kMMFlagsPCD | HAL::kMMFlagsPwt); + + UInt32 ports_implemented = mem_ahci->Pi; + UInt16 ahci_index = 0; + + pi = ports_implemented; + + const UInt16 kSATAMaxPortsImplemented = ports_implemented; + const UInt32 kSATASignature = kSATASig; + const UInt32 kSATAPISignature = kSATAPISig; + const UInt8 kSATAPresent = 0x03; + const UInt8 kSATAIPMActive = 0x01; + + if (kSATAMaxPortsImplemented < 1) continue; + + while (ports_implemented) { + UInt8 ipm = (mem_ahci->Ports[ahci_index].Ssts >> 8) & 0x0F; + UInt8 det = (mem_ahci->Ports[ahci_index].Ssts & 0x0F); + + if (det != kSATAPresent || ipm != kSATAIPMActive) continue; + + if ((mem_ahci->Ports[ahci_index].Sig == kSATASignature) || + (atapi && kSATAPISignature == mem_ahci->Ports[ahci_index].Sig)) { + kSATAIndex = ahci_index; + kSATAHba = mem_ahci; + + if (!drv_init_command_structures_ahci()) { + err_global_get() = kErrorDisk; + } + + goto success_hba_fetch; + } + + ports_implemented >>= 1; + ++ahci_index; + } + } + } + + err_global_get() = kErrorDisk; + + return NO; + +success_hba_fetch: + if (ahci_enable_and_probe()) { + err_global_get() = kErrorSuccess; + } + + return err_global_get() == kErrorSuccess; +} + +/// @brief Checks if an AHCI device is detected. +/// @return Either if detected, or not found. +Bool drv_std_detected_ahci() { + return kSATADev.DeviceId() != (UShort) PCI::PciConfigKind::Invalid && + kSATADev.Bar(kSATABar5) != 0; +} + +// ================================================================================================ + +// +/// @note This applies only if we compile with AHCI as a default disk driver. +// + +// ================================================================================================ + +#ifdef __AHCI__ + +//////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////// +Void drv_std_write(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) { + drv_std_input_output_ahci(lba, reinterpret_cast(buffer), sector_sz, + size_buffer); +} + +//////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////// +Void drv_std_read(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) { + drv_std_input_output_ahci(lba, reinterpret_cast(buffer), sector_sz, + size_buffer); +} + +//////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////// +Bool drv_std_init(UInt16& pi) { + BOOL atapi = NO; + return drv_std_init_ahci(pi, atapi); +} + +//////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////// +Bool drv_std_detected(Void) { + return drv_std_detected_ahci(); +} + +//////////////////////////////////////////////////// +/** + @brief Gets the number of sectors inside the drive. + @return Sector size in bytes. + */ +//////////////////////////////////////////////////// +SizeT drv_std_get_sector_count() { + return drv_get_sector_count_ahci(); +} + +//////////////////////////////////////////////////// +/// @brief Get the drive size. +/// @return Disk size in bytes. +//////////////////////////////////////////////////// +SizeT drv_std_get_size() { + return drv_get_size_ahci(); +} + +#endif // ifdef __AHCI__ + +namespace Kernel { +/// @brief Initialize an AHCI device (StorageKit) +UInt16 sk_init_ahci_device(BOOL atapi) { + UInt16 pi = 0; + + if (drv_std_init_ahci(pi, atapi)) kSATAPortsImplemented = pi; + + return pi; +} + +/// @brief Implementation details namespace. +namespace Detail { + /// @brief Read AHCI device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_read_ahci(IDevice* self, IMountpoint* mnt) { + AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; + + err_global_get() = kErrorDisk; + + if (!dev) return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) return; + + err_global_get() = kErrorSuccess; + + drv_std_input_output_ahci(disk->fPacket.fPacketLba / kAHCISectorSize, + (UInt8*) disk->fPacket.fPacketContent, kAHCISectorSize, + disk->fPacket.fPacketSize); + } + + /// @brief Write AHCI device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_write_ahci(IDevice* self, IMountpoint* mnt) { + AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; + + err_global_get() = kErrorDisk; + + if (!dev) return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) return; + + err_global_get() = kErrorSuccess; + + drv_std_input_output_ahci(disk->fPacket.fPacketLba / kAHCISectorSize, + (UInt8*) disk->fPacket.fPacketContent, kAHCISectorSize, + disk->fPacket.fPacketSize); + } +} // namespace Detail + +/// @brief Acquires a new AHCI device with drv_index in mind. +/// @param drv_index The drive index to assign. +/// @return A wrapped device interface if successful, or error code. +ErrorOr sk_acquire_ahci_device(UInt32 drv_index) { + if (!drv_std_detected_ahci()) return ErrorOr(kErrorDisk); + + AHCIDeviceInterface device(Detail::sk_io_read_ahci, Detail::sk_io_write_ahci); + + device.SetPortsImplemented(kSATAPortsImplemented); + device.SetIndex(drv_index); + + return ErrorOr(device); +} +} // namespace Kernel diff --git a/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc b/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc deleted file mode 100644 index 8bf7b161..00000000 --- a/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -#if defined(__ATA_DMA__) - -#define kATADataLen (256) - -using namespace Kernel; -using namespace Kernel::HAL; - -/// BUGS: 0 - -STATIC Boolean kATADetected = false; -STATIC Int32 kATADeviceType ATTRIBUTE(unused) = kATADeviceCount; -STATIC UInt16 kATAIdentifyData[kATADataLen] = {0}; -STATIC Kernel::PCI::Device kATADevice; -STATIC Char kATADiskModel[50] ATTRIBUTE(unused) = {"GENERIC DMA"}; - -Boolean drv_std_wait_io(UInt16 IO) { - for (int i = 0; i < 400; i++) rt_in8(IO + ATA_REG_STATUS); - -ATAWaitForIO_Retry: - auto status_rdy = rt_in8(IO + ATA_REG_STATUS); - - if ((status_rdy & ATA_SR_BSY)) goto ATAWaitForIO_Retry; - -ATAWaitForIO_Retry2: - status_rdy = rt_in8(IO + ATA_REG_STATUS); - - if (status_rdy & ATA_SR_ERR) return false; - - if (!(status_rdy & ATA_SR_DRDY)) goto ATAWaitForIO_Retry2; - - return true; -} - -Void drv_std_select(UInt16 Bus) { - if (Bus == ATA_PRIMARY_IO) - rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); - else - rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); -} - -Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { - NE_UNUSED(Bus); - NE_UNUSED(Drive); - NE_UNUSED(OutBus); - NE_UNUSED(OutMaster); - - PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); - - for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) { - kATADevice = iterator[device_index].Leak(); // And then leak the reference. - - /// IDE interface - if (kATADevice.Subclass() == 0x01) { - break; - } - } - - return NO; -} - -namespace Kernel::Detail { -struct PRDEntry final { - UInt32 mAddress; - UInt16 mByteCount; - UInt16 mFlags; /// @param PRD flags, set to 0x8000 to indicate end of prd. -}; -} // namespace Kernel::Detail - -static UIntPtr kReadAddr = mib_cast(2); -static UIntPtr kWriteAddr = mib_cast(2) + kib_cast(64); - -Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { - Lba /= SectorSz; - - if (Size > kib_cast(64)) return; - - UInt8 Command = ((!Master) ? 0xE0 : 0xF0); - - rt_copy_memory((VoidPtr) Buf, (VoidPtr) kReadAddr, Size); - - drv_std_select(IO); - - rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); - - rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz - 1) / SectorSz)); - - rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); - rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); - rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); - rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); - - Kernel::Detail::PRDEntry* prd = - (Kernel::Detail::PRDEntry*) (kATADevice.Bar(0x20) + 4); // The PRDEntry is not correct. - - prd->mAddress = (UInt32) (UIntPtr) kReadAddr; - prd->mByteCount = Size - 1; - prd->mFlags = 0x8000; // indicate the end of prd. - - rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32) (UIntPtr) prd); - - rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_READ_DMA); - - rt_out8(kATADevice.Bar(0x20) + 0x00, 0x09); // Start DMA engine - - while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01); - - rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine - - rt_copy_memory((VoidPtr) kReadAddr, (VoidPtr) Buf, Size); - - delete prd; - prd = nullptr; -} - -Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { - Lba /= SectorSz; - - if (Size > kib_cast(64)) return; - - UInt8 Command = ((!Master) ? 0xE0 : 0xF0); - - rt_copy_memory((VoidPtr) Buf, (VoidPtr) kWriteAddr, Size); - - rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); - - rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + (SectorSz - 1)) / SectorSz)); - - rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); - rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); - rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); - rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); - - Kernel::Detail::PRDEntry* prd = (Kernel::Detail::PRDEntry*) (kATADevice.Bar(0x20) + 4); - - prd->mAddress = (UInt32) (UIntPtr) kWriteAddr; - prd->mByteCount = Size - 1; - prd->mFlags = 0x8000; - - rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32) (UIntPtr) prd); - rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA); - - rt_out8(IO + 0x00, 0x09); // Start DMA engine - - while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01); - - rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine - - delete prd; - prd = nullptr; -} - -/***********************************************************************************/ -/// @brief Is ATA detected? -/***********************************************************************************/ -Boolean drv_std_detected(Void) { - return kATADetected; -} - -/***********************************************************************************/ -/*** - @brief Gets the number of sectors inside the drive. - @return Number of sectors, or zero. -*/ -/***********************************************************************************/ -Kernel::SizeT drv_std_get_sector_count() { - return (kATAIdentifyData[61] << 16) | kATAIdentifyData[60]; -} - -/***********************************************************************************/ -/// @brief Get the size of the current drive. -/***********************************************************************************/ -Kernel::SizeT drv_std_get_size() { - return (drv_std_get_sector_count()) * kATASectorSize; -} - -#endif /* ifdef __ATA_DMA__ */ diff --git a/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cpp b/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cpp new file mode 100644 index 00000000..8bf7b161 --- /dev/null +++ b/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cpp @@ -0,0 +1,184 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +#if defined(__ATA_DMA__) + +#define kATADataLen (256) + +using namespace Kernel; +using namespace Kernel::HAL; + +/// BUGS: 0 + +STATIC Boolean kATADetected = false; +STATIC Int32 kATADeviceType ATTRIBUTE(unused) = kATADeviceCount; +STATIC UInt16 kATAIdentifyData[kATADataLen] = {0}; +STATIC Kernel::PCI::Device kATADevice; +STATIC Char kATADiskModel[50] ATTRIBUTE(unused) = {"GENERIC DMA"}; + +Boolean drv_std_wait_io(UInt16 IO) { + for (int i = 0; i < 400; i++) rt_in8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if ((status_rdy & ATA_SR_BSY)) goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (status_rdy & ATA_SR_ERR) return false; + + if (!(status_rdy & ATA_SR_DRDY)) goto ATAWaitForIO_Retry2; + + return true; +} + +Void drv_std_select(UInt16 Bus) { + if (Bus == ATA_PRIMARY_IO) + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { + NE_UNUSED(Bus); + NE_UNUSED(Drive); + NE_UNUSED(OutBus); + NE_UNUSED(OutMaster); + + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); + + for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) { + kATADevice = iterator[device_index].Leak(); // And then leak the reference. + + /// IDE interface + if (kATADevice.Subclass() == 0x01) { + break; + } + } + + return NO; +} + +namespace Kernel::Detail { +struct PRDEntry final { + UInt32 mAddress; + UInt16 mByteCount; + UInt16 mFlags; /// @param PRD flags, set to 0x8000 to indicate end of prd. +}; +} // namespace Kernel::Detail + +static UIntPtr kReadAddr = mib_cast(2); +static UIntPtr kWriteAddr = mib_cast(2) + kib_cast(64); + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { + Lba /= SectorSz; + + if (Size > kib_cast(64)) return; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + rt_copy_memory((VoidPtr) Buf, (VoidPtr) kReadAddr, Size); + + drv_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz - 1) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + Kernel::Detail::PRDEntry* prd = + (Kernel::Detail::PRDEntry*) (kATADevice.Bar(0x20) + 4); // The PRDEntry is not correct. + + prd->mAddress = (UInt32) (UIntPtr) kReadAddr; + prd->mByteCount = Size - 1; + prd->mFlags = 0x8000; // indicate the end of prd. + + rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32) (UIntPtr) prd); + + rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_READ_DMA); + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x09); // Start DMA engine + + while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01); + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine + + rt_copy_memory((VoidPtr) kReadAddr, (VoidPtr) Buf, Size); + + delete prd; + prd = nullptr; +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { + Lba /= SectorSz; + + if (Size > kib_cast(64)) return; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + rt_copy_memory((VoidPtr) Buf, (VoidPtr) kWriteAddr, Size); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + (SectorSz - 1)) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + Kernel::Detail::PRDEntry* prd = (Kernel::Detail::PRDEntry*) (kATADevice.Bar(0x20) + 4); + + prd->mAddress = (UInt32) (UIntPtr) kWriteAddr; + prd->mByteCount = Size - 1; + prd->mFlags = 0x8000; + + rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32) (UIntPtr) prd); + rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA); + + rt_out8(IO + 0x00, 0x09); // Start DMA engine + + while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01); + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine + + delete prd; + prd = nullptr; +} + +/***********************************************************************************/ +/// @brief Is ATA detected? +/***********************************************************************************/ +Boolean drv_std_detected(Void) { + return kATADetected; +} + +/***********************************************************************************/ +/*** + @brief Gets the number of sectors inside the drive. + @return Number of sectors, or zero. +*/ +/***********************************************************************************/ +Kernel::SizeT drv_std_get_sector_count() { + return (kATAIdentifyData[61] << 16) | kATAIdentifyData[60]; +} + +/***********************************************************************************/ +/// @brief Get the size of the current drive. +/***********************************************************************************/ +Kernel::SizeT drv_std_get_size() { + return (drv_std_get_sector_count()) * kATASectorSize; +} + +#endif /* ifdef __ATA_DMA__ */ diff --git a/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc b/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc deleted file mode 100644 index 7b0726e7..00000000 --- a/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -using namespace Kernel; diff --git a/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cpp b/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cpp new file mode 100644 index 00000000..7b0726e7 --- /dev/null +++ b/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cpp @@ -0,0 +1,7 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +using namespace Kernel; diff --git a/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc deleted file mode 100644 index 19497b5f..00000000 --- a/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include - -using namespace Kernel; -using namespace Kernel::HAL; - -/// BUGS: 0 - -#define kATADataLen 256 - -STATIC Boolean kATADetected = false; -STATIC UInt16 kATAIdentifyData[kATADataLen] = {0}; -STATIC Char kATADiskModel[50] = {"GENERIC PIO"}; - -static Boolean drv_pio_std_wait_io(UInt16 IO) { - for (int i = 0; i < 400; i++) rt_in8(IO + ATA_REG_STATUS); - -ATAWaitForIO_Retry: - auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); - - if ((stat_rdy & ATA_SR_BSY)) goto ATAWaitForIO_Retry; - -ATAWaitForIO_Retry2: - stat_rdy = rt_in8(IO + ATA_REG_STATUS); - - if (stat_rdy & ATA_SR_ERR) return false; - - if (!(stat_rdy & ATA_SR_DRDY)) goto ATAWaitForIO_Retry2; - - return true; -} - -STATIC Void drv_pio_std_select(UInt16 Bus) { - if (Bus == ATA_PRIMARY_IO) - rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); - else - rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); -} - -Boolean drv_pio_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { - UInt16 IO = Bus; - - NE_UNUSED(Drive); - - drv_pio_std_select(IO); - - // Bus init, NEIN bit. - rt_out8(IO + ATA_REG_NEIN, 1); - - // identify until it's good. -ATAInit_Retry: - auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); - - if (stat_rdy & ATA_SR_ERR) { - return false; - } - - if ((stat_rdy & ATA_SR_BSY)) goto ATAInit_Retry; - - OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; - OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; - - drv_pio_std_select(IO); - - rt_out8(OutBus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - - while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRQ)); - - /// fetch serial info - /// model, speed, number of sectors... - - for (SizeT i = 0ul; i < kATADataLen; ++i) { - kATAIdentifyData[i] = rt_in16(OutBus + ATA_REG_DATA); - } - - for (Int32 i = 0; i < 20; i++) { - kATADiskModel[i * 2] = (kATAIdentifyData[27 + i] >> 8) & 0xFF; - kATADiskModel[i * 2 + 1] = kATAIdentifyData[27 + i] & 0xFF; - } - - kATADiskModel[40] = '\0'; - - (Void)(kout << "Drive Model: " << kATADiskModel << kendl); - - return true; -} - -Void drv_pio_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { - Lba /= SectorSz; - - UInt8 Command = ((!Master) ? 0xE0 : 0xF0); - - drv_pio_std_wait_io(IO); - drv_pio_std_select(IO); - - rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); - - rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz) / SectorSz)); - - rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); - rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); - rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); - rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); - - rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); - - while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRQ)); - - for (SizeT IndexOff = 0; IndexOff < Size; IndexOff += 2) { - drv_pio_std_wait_io(IO); - - auto in = rt_in16(IO + ATA_REG_DATA); - - Buf[IndexOff] = in & 0xFF; - Buf[IndexOff + 1] = (in >> 8) & 0xFF; - } -} - -Void drv_pio_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { - Lba /= SectorSz; - - UInt8 Command = ((!Master) ? 0xE0 : 0xF0); - - drv_pio_std_wait_io(IO); - drv_pio_std_select(IO); - - rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); - - rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz) / SectorSz)); - - rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); - rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); - rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); - rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); - - rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); - - while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRQ)); - - for (SizeT IndexOff = 0; IndexOff < Size; IndexOff += 2) { - drv_pio_std_wait_io(IO); - - UInt8 low = (UInt8) Buf[IndexOff]; - UInt8 high = (IndexOff + 1 < Size) ? (UInt8) Buf[IndexOff + 1] : 0; - UInt16 packed = (high << 8) | low; - - rt_out16(IO + ATA_REG_DATA, packed); - } -} - -/// @brief is ATA detected? -Boolean drv_pio_std_detected(Void) { - return kATADetected; -} - -/*** - @brief Getter, gets the number of sectors inside the drive. - */ -SizeT drv_pio_get_sector_count() { - return (kATAIdentifyData[61] << 16) | kATAIdentifyData[60]; -} - -/// @brief Get the drive size. -SizeT drv_pio_get_size() { - return (drv_pio_get_sector_count()) * kATASectorSize; -} - -namespace Kernel { -/// @brief Initialize an PIO device (StorageKit function) -/// @param is_master is the current PIO master? -/// @return [io:master] for PIO device. -BOOL sk_init_ata_device(BOOL is_master, UInt16& io, UInt8& master) { - return drv_pio_std_init(ATA_SECONDARY_IO, is_master, io, master); -} - -/// @brief Implementation details namespace. -namespace Detail { - /// @brief Read PIO device. - /// @param self device - /// @param mnt mounted disk. - STATIC Void sk_io_read_pio(IDevice* self, IMountpoint* mnt) { - ATADeviceInterface* dev = (ATADeviceInterface*) self; - - err_global_get() = kErrorDisk; - - if (!dev) return; - - auto disk = mnt->GetAddressOf(dev->GetIndex()); - - if (!disk) return; - - err_global_get() = kErrorSuccess; - - drv_pio_std_read(disk->fPacket.fPacketLba, dev->GetIO(), dev->GetMaster(), - (Char*) disk->fPacket.fPacketContent, kATASectorSize, - disk->fPacket.fPacketSize); - } - - /// @brief Write PIO device. - /// @param self device - /// @param mnt mounted disk. - STATIC Void sk_io_write_pio(IDevice* self, IMountpoint* mnt) { - ATADeviceInterface* dev = (ATADeviceInterface*) self; - - err_global_get() = kErrorDisk; - - if (!dev) return; - - auto disk = mnt->GetAddressOf(dev->GetIndex()); - - if (!disk) return; - - err_global_get() = kErrorSuccess; - - drv_pio_std_write(disk->fPacket.fPacketLba, dev->GetIO(), dev->GetMaster(), - (Char*) disk->fPacket.fPacketContent, kATASectorSize, - disk->fPacket.fPacketSize); - } -} // namespace Detail - -/// @brief Acquires a new PIO device with drv_index in mind. -/// @param drv_index The drive index to assign. -/// @return A wrapped device interface if successful, or error code. -ErrorOr sk_acquire_ata_device(Int32 drv_index) { - /// here we don't check if we probed ATA, since we'd need to grab IO after that. - ATADeviceInterface device(Detail::sk_io_read_pio, Detail::sk_io_write_pio); - - device.SetIndex(drv_index); - - return ErrorOr(device); -} -} // namespace Kernel - -#ifdef __ATA_PIO__ - -Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { - drv_pio_std_read(Lba, IO, Master, Buf, SectorSz, Size); -} - -Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { - drv_pio_std_write(Lba, IO, Master, Buf, SectorSz, Size); -} - -SizeT drv_std_get_size() { - return drv_pio_get_size(); -} - -SizeT drv_std_get_sector_count() { - return drv_pio_get_sector_count(); -} - -Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { - return drv_pio_std_init(Bus, Drive, OutBus, OutMaster); -} - -#endif \ No newline at end of file diff --git a/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cpp b/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cpp new file mode 100644 index 00000000..19497b5f --- /dev/null +++ b/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cpp @@ -0,0 +1,262 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include + +using namespace Kernel; +using namespace Kernel::HAL; + +/// BUGS: 0 + +#define kATADataLen 256 + +STATIC Boolean kATADetected = false; +STATIC UInt16 kATAIdentifyData[kATADataLen] = {0}; +STATIC Char kATADiskModel[50] = {"GENERIC PIO"}; + +static Boolean drv_pio_std_wait_io(UInt16 IO) { + for (int i = 0; i < 400; i++) rt_in8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if ((stat_rdy & ATA_SR_BSY)) goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (stat_rdy & ATA_SR_ERR) return false; + + if (!(stat_rdy & ATA_SR_DRDY)) goto ATAWaitForIO_Retry2; + + return true; +} + +STATIC Void drv_pio_std_select(UInt16 Bus) { + if (Bus == ATA_PRIMARY_IO) + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_pio_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { + UInt16 IO = Bus; + + NE_UNUSED(Drive); + + drv_pio_std_select(IO); + + // Bus init, NEIN bit. + rt_out8(IO + ATA_REG_NEIN, 1); + + // identify until it's good. +ATAInit_Retry: + auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (stat_rdy & ATA_SR_ERR) { + return false; + } + + if ((stat_rdy & ATA_SR_BSY)) goto ATAInit_Retry; + + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + + drv_pio_std_select(IO); + + rt_out8(OutBus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + + while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRQ)); + + /// fetch serial info + /// model, speed, number of sectors... + + for (SizeT i = 0ul; i < kATADataLen; ++i) { + kATAIdentifyData[i] = rt_in16(OutBus + ATA_REG_DATA); + } + + for (Int32 i = 0; i < 20; i++) { + kATADiskModel[i * 2] = (kATAIdentifyData[27 + i] >> 8) & 0xFF; + kATADiskModel[i * 2 + 1] = kATAIdentifyData[27 + i] & 0xFF; + } + + kATADiskModel[40] = '\0'; + + (Void)(kout << "Drive Model: " << kATADiskModel << kendl); + + return true; +} + +Void drv_pio_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { + Lba /= SectorSz; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + drv_pio_std_wait_io(IO); + drv_pio_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRQ)); + + for (SizeT IndexOff = 0; IndexOff < Size; IndexOff += 2) { + drv_pio_std_wait_io(IO); + + auto in = rt_in16(IO + ATA_REG_DATA); + + Buf[IndexOff] = in & 0xFF; + Buf[IndexOff + 1] = (in >> 8) & 0xFF; + } +} + +Void drv_pio_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { + Lba /= SectorSz; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + drv_pio_std_wait_io(IO); + drv_pio_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); + + while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRQ)); + + for (SizeT IndexOff = 0; IndexOff < Size; IndexOff += 2) { + drv_pio_std_wait_io(IO); + + UInt8 low = (UInt8) Buf[IndexOff]; + UInt8 high = (IndexOff + 1 < Size) ? (UInt8) Buf[IndexOff + 1] : 0; + UInt16 packed = (high << 8) | low; + + rt_out16(IO + ATA_REG_DATA, packed); + } +} + +/// @brief is ATA detected? +Boolean drv_pio_std_detected(Void) { + return kATADetected; +} + +/*** + @brief Getter, gets the number of sectors inside the drive. + */ +SizeT drv_pio_get_sector_count() { + return (kATAIdentifyData[61] << 16) | kATAIdentifyData[60]; +} + +/// @brief Get the drive size. +SizeT drv_pio_get_size() { + return (drv_pio_get_sector_count()) * kATASectorSize; +} + +namespace Kernel { +/// @brief Initialize an PIO device (StorageKit function) +/// @param is_master is the current PIO master? +/// @return [io:master] for PIO device. +BOOL sk_init_ata_device(BOOL is_master, UInt16& io, UInt8& master) { + return drv_pio_std_init(ATA_SECONDARY_IO, is_master, io, master); +} + +/// @brief Implementation details namespace. +namespace Detail { + /// @brief Read PIO device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_read_pio(IDevice* self, IMountpoint* mnt) { + ATADeviceInterface* dev = (ATADeviceInterface*) self; + + err_global_get() = kErrorDisk; + + if (!dev) return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) return; + + err_global_get() = kErrorSuccess; + + drv_pio_std_read(disk->fPacket.fPacketLba, dev->GetIO(), dev->GetMaster(), + (Char*) disk->fPacket.fPacketContent, kATASectorSize, + disk->fPacket.fPacketSize); + } + + /// @brief Write PIO device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_write_pio(IDevice* self, IMountpoint* mnt) { + ATADeviceInterface* dev = (ATADeviceInterface*) self; + + err_global_get() = kErrorDisk; + + if (!dev) return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) return; + + err_global_get() = kErrorSuccess; + + drv_pio_std_write(disk->fPacket.fPacketLba, dev->GetIO(), dev->GetMaster(), + (Char*) disk->fPacket.fPacketContent, kATASectorSize, + disk->fPacket.fPacketSize); + } +} // namespace Detail + +/// @brief Acquires a new PIO device with drv_index in mind. +/// @param drv_index The drive index to assign. +/// @return A wrapped device interface if successful, or error code. +ErrorOr sk_acquire_ata_device(Int32 drv_index) { + /// here we don't check if we probed ATA, since we'd need to grab IO after that. + ATADeviceInterface device(Detail::sk_io_read_pio, Detail::sk_io_write_pio); + + device.SetIndex(drv_index); + + return ErrorOr(device); +} +} // namespace Kernel + +#ifdef __ATA_PIO__ + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { + drv_pio_std_read(Lba, IO, Master, Buf, SectorSz, Size); +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { + drv_pio_std_write(Lba, IO, Master, Buf, SectorSz, Size); +} + +SizeT drv_std_get_size() { + return drv_pio_get_size(); +} + +SizeT drv_std_get_sector_count() { + return drv_pio_get_sector_count(); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { + return drv_pio_std_init(Bus, Drive, OutBus, OutMaster); +} + +#endif \ No newline at end of file diff --git a/src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cc b/src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cc deleted file mode 100644 index f73946d7..00000000 --- a/src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cc +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -using namespace Kernel; - -///! @brief ATAPI SCSI packet. -const ATTRIBUTE(unused) scsi_packet_type_12 kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, - 0, 12, 0x40, 0, 0}; diff --git a/src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cpp b/src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cpp new file mode 100644 index 00000000..f73946d7 --- /dev/null +++ b/src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cpp @@ -0,0 +1,11 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +using namespace Kernel; + +///! @brief ATAPI SCSI packet. +const ATTRIBUTE(unused) scsi_packet_type_12 kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, + 0, 12, 0x40, 0, 0}; diff --git a/src/kernel/HALKit/ARM64/APM/APM+IO.cc b/src/kernel/HALKit/ARM64/APM/APM+IO.cc deleted file mode 100644 index 91b8255e..00000000 --- a/src/kernel/HALKit/ARM64/APM/APM+IO.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -using namespace Kernel; - -/// @brief Send APM command to its IO space. -/// @param base_dma the IO base port. -/// @param cmd the command. -/// @return status code. -EXTERN_C Int32 apm_send_io_command(UInt16 cmd) { - switch (cmd) { - case kAPMPowerCommandReboot: { - asm volatile( - "ldr x0, =0x84000004\n" - "svc #0\n"); - - return kErrorSuccess; - } - case kAPMPowerCommandShutdown: { - asm volatile( - "ldr x0, =0x84000008\n" - "svc #0\n"); - - return kErrorSuccess; - } - default: - return kErrorInvalidData; - } -} diff --git a/src/kernel/HALKit/ARM64/APM/APM+IO.cpp b/src/kernel/HALKit/ARM64/APM/APM+IO.cpp new file mode 100644 index 00000000..91b8255e --- /dev/null +++ b/src/kernel/HALKit/ARM64/APM/APM+IO.cpp @@ -0,0 +1,33 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +using namespace Kernel; + +/// @brief Send APM command to its IO space. +/// @param base_dma the IO base port. +/// @param cmd the command. +/// @return status code. +EXTERN_C Int32 apm_send_io_command(UInt16 cmd) { + switch (cmd) { + case kAPMPowerCommandReboot: { + asm volatile( + "ldr x0, =0x84000004\n" + "svc #0\n"); + + return kErrorSuccess; + } + case kAPMPowerCommandShutdown: { + asm volatile( + "ldr x0, =0x84000008\n" + "svc #0\n"); + + return kErrorSuccess; + } + default: + return kErrorInvalidData; + } +} diff --git a/src/kernel/HALKit/ARM64/CxxAbi.cc b/src/kernel/HALKit/ARM64/CxxAbi.cc deleted file mode 100644 index 7b19aa71..00000000 --- a/src/kernel/HALKit/ARM64/CxxAbi.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; - -uarch_t __atexit_func_count; - -/// @brief dynamic shared object Handle. -Kernel::UIntPtr __dso_handle; - -EXTERN_C void __chkstk(void) {} - -EXTERN_C int atexit(void (*f)(), void* arg, void* dso) { - if (__atexit_func_count >= kAtExitMacDestructors) return 1; - - __atexit_funcs[__atexit_func_count].destructor_func = f; - __atexit_funcs[__atexit_func_count].obj_ptr = arg; - __atexit_funcs[__atexit_func_count].dso_handle = dso; - - __atexit_func_count++; - - return 0; -} - -EXTERN_C void __cxa_finalize(void* f) { - uarch_t i = __atexit_func_count; - if (!f) { - while (i--) { - if (__atexit_funcs[i].destructor_func) { - (*__atexit_funcs[i].destructor_func)(); - __atexit_funcs[i].destructor_func = 0; - }; - } - - return; - } - - while (i--) { - if (__atexit_funcs[i].destructor_func) { - (*__atexit_funcs[i].destructor_func)(); - __atexit_funcs[i].destructor_func = 0; - }; - } -} - -namespace cxxabiv1 { -EXTERN_C int __cxa_guard_acquire(__guard* g) { - (void) g; - return 0; -} - -EXTERN_C int __cxa_guard_release(__guard* g) { - *(char*) g = 1; - return 0; -} - -EXTERN_C void __cxa_guard_abort(__guard* g) { - (void) g; -} -} // namespace cxxabiv1 - -EXTERN_C Kernel::Void _purecall(void* self) { - (Kernel::Void)(Kernel::kout << "object: " - << Kernel::number(reinterpret_cast(self))); - (Kernel::Void)(Kernel::kout << ", has unimplemented virtual functions.\r"); -} - -EXTERN_C Kernel::Void _Init_thread_footer(Kernel::Int* thread_obj) { - NE_UNUSED(thread_obj); -} - -EXTERN_C Kernel::Void _Init_thread_epoch(Kernel::Void) { - NE_UNUSED(0); -} - -EXTERN_C Kernel::Void _Init_thread_header(Kernel::Int* thread_obj) { - NE_UNUSED(0); -} - -EXTERN_C Kernel::Int _tls_index = 0UL; diff --git a/src/kernel/HALKit/ARM64/CxxAbi.cpp b/src/kernel/HALKit/ARM64/CxxAbi.cpp new file mode 100644 index 00000000..7b19aa71 --- /dev/null +++ b/src/kernel/HALKit/ARM64/CxxAbi.cpp @@ -0,0 +1,85 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; + +uarch_t __atexit_func_count; + +/// @brief dynamic shared object Handle. +Kernel::UIntPtr __dso_handle; + +EXTERN_C void __chkstk(void) {} + +EXTERN_C int atexit(void (*f)(), void* arg, void* dso) { + if (__atexit_func_count >= kAtExitMacDestructors) return 1; + + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = arg; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + + __atexit_func_count++; + + return 0; +} + +EXTERN_C void __cxa_finalize(void* f) { + uarch_t i = __atexit_func_count; + if (!f) { + while (i--) { + if (__atexit_funcs[i].destructor_func) { + (*__atexit_funcs[i].destructor_func)(); + __atexit_funcs[i].destructor_func = 0; + }; + } + + return; + } + + while (i--) { + if (__atexit_funcs[i].destructor_func) { + (*__atexit_funcs[i].destructor_func)(); + __atexit_funcs[i].destructor_func = 0; + }; + } +} + +namespace cxxabiv1 { +EXTERN_C int __cxa_guard_acquire(__guard* g) { + (void) g; + return 0; +} + +EXTERN_C int __cxa_guard_release(__guard* g) { + *(char*) g = 1; + return 0; +} + +EXTERN_C void __cxa_guard_abort(__guard* g) { + (void) g; +} +} // namespace cxxabiv1 + +EXTERN_C Kernel::Void _purecall(void* self) { + (Kernel::Void)(Kernel::kout << "object: " + << Kernel::number(reinterpret_cast(self))); + (Kernel::Void)(Kernel::kout << ", has unimplemented virtual functions.\r"); +} + +EXTERN_C Kernel::Void _Init_thread_footer(Kernel::Int* thread_obj) { + NE_UNUSED(thread_obj); +} + +EXTERN_C Kernel::Void _Init_thread_epoch(Kernel::Void) { + NE_UNUSED(0); +} + +EXTERN_C Kernel::Void _Init_thread_header(Kernel::Int* thread_obj) { + NE_UNUSED(0); +} + +EXTERN_C Kernel::Int _tls_index = 0UL; diff --git a/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc b/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc deleted file mode 100644 index 544d1ee1..00000000 --- a/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include - -namespace Kernel { -ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) : fRsdp(rsp_ptr), fEntries(0) {} - -BOOL ACPIFactoryInterface::Shutdown() { - apm_send_io_command(kAPMPowerCommandShutdown); - return NO; -} - -/// @brief Reboot machine in either ACPI or by triple faulting. -/// @return nothing it's a reboot. -Void ACPIFactoryInterface::Reboot() { - apm_send_io_command(kAPMPowerCommandReboot); -} -} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cpp b/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cpp new file mode 100644 index 00000000..544d1ee1 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cpp @@ -0,0 +1,24 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include + +namespace Kernel { +ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) : fRsdp(rsp_ptr), fEntries(0) {} + +BOOL ACPIFactoryInterface::Shutdown() { + apm_send_io_command(kAPMPowerCommandShutdown); + return NO; +} + +/// @brief Reboot machine in either ACPI or by triple faulting. +/// @return nothing it's a reboot. +Void ACPIFactoryInterface::Reboot() { + apm_send_io_command(kAPMPowerCommandReboot); +} +} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalApplicationProcessor.cc b/src/kernel/HALKit/ARM64/HalApplicationProcessor.cc deleted file mode 100644 index 33921a56..00000000 --- a/src/kernel/HALKit/ARM64/HalApplicationProcessor.cc +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#define GICD_BASE 0x08000000 -#define GICC_BASE 0x08010000 - -#define GICD_CTLR 0x000 -#define GICD_ISENABLER 0x100 -#define GICD_ICENABLER 0x180 -#define GICD_ISPENDR 0x200 -#define GICD_ICPENDR 0x280 -#define GICD_IPRIORITYR 0x400 -#define GICD_ITARGETSR 0x800 -#define GICD_ICFGR 0xC00 - -#define GICC_CTLR 0x000 -#define GICC_PMR 0x004 -#define GICC_IAR 0x00C -#define GICC_EOIR 0x010 - -#include -#include -#include -#include -#include -#include - -// ================================================================= // - -namespace Kernel { -struct HAL_HARDWARE_THREAD final { - HAL::StackFramePtr mFramePtr; - ProcessID mThreadID{0}; -}; - -STATIC HAL_HARDWARE_THREAD kHWThread[kMaxAPInsideSched] = {{nullptr}}; - -namespace Detail { - STATIC BOOL kGICEnabled = NO; - - /***********************************************************************************/ - /// @brief Enables the GIC with EL0 configuration. - /// @internal - /***********************************************************************************/ - STATIC Void mp_setup_gic_el0(Void) { - ke_dma_write(GICD_BASE, GICD_CTLR, YES); - - UInt32 gicc_ctlr = ke_dma_read(GICC_BASE, GICC_CTLR); - - const UInt8 kEnableSignalInt = 0x1; - - gicc_ctlr |= kEnableSignalInt; - gicc_ctlr |= (kEnableSignalInt << 0x1); - - ke_dma_write(GICC_BASE, GICC_CTLR, gicc_ctlr); - - ke_dma_write(GICC_BASE, GICC_PMR, 0xFF); - - UInt32 icfgr = ke_dma_read(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4); - - icfgr |= (0x2 << ((32 % 16) * 2)); - - ke_dma_write(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4, icfgr); - ke_dma_write(GICD_BASE, GICD_ITARGETSR + (0x20 / 0x04) * 4, 0x2 << ((32 % 4) * 8)); - ke_dma_write(GICD_BASE, GICD_IPRIORITYR + (0x20 / 0x04) * 4, 0xFF << ((32 % 4) * 8)); - ke_dma_write(GICD_BASE, GICD_ISENABLER + 4, 0x01); - } - - EXTERN_C BOOL mp_handle_gic_interrupt_el0(Void) { - UInt32 interrupt_id = ke_dma_read(GICC_BASE, GICC_IAR); - - if ((interrupt_id & 0x3FF) < 1020) { - auto interrupt = interrupt_id & 0x3FF; - - const UInt16 kInterruptScheduler = 0x20; - - (Void)(kout << "SMP: AP: " << hex_number(interrupt) << kendl); - - switch (interrupt) { - case kInterruptScheduler: { - ke_dma_write(GICC_BASE, GICC_EOIR, interrupt_id); - UserProcessHelper::StartScheduling(); - break; - } - default: { - ke_dma_write(GICC_BASE, GICC_EOIR, interrupt_id); - break; - } - } - - return YES; - } - - return NO; - } -} // namespace Detail - -/***********************************************************************************/ -/// @brief Get current stack frame for a thread. -/// @param thrdid The thread ID. -/***********************************************************************************/ - -EXTERN_C HAL::StackFramePtr mp_get_current_task(ProcessID thrdid) { - return kHWThread[thrdid].mFramePtr; -} - -/***********************************************************************************/ -/// @brief Register current stack frame for a thread. -/// @param stack_frame The current stack frame. -/// @param thrdid The thread ID. -/***********************************************************************************/ - -EXTERN_C Bool mp_register_task(HAL::StackFramePtr stack_frame, ProcessID thrdid) { - MUST_PASS(Detail::kGICEnabled); - - if (!stack_frame) return NO; - if (thrdid > kMaxAPInsideSched) return NO; - - const auto process_index = thrdid; - - kHWThread[process_index].mFramePtr = stack_frame; - kHWThread[process_index].mThreadID = thrdid; - - return YES; -} - -/***********************************************************************************/ -/// @brief Initialize the Global Interrupt Controller. -/// @internal -/***********************************************************************************/ -Void mp_init_cores(Void) { - if (!Detail::kGICEnabled) { - Detail::kGICEnabled = YES; - Detail::mp_setup_gic_el0(); - } -} -} // namespace Kernel \ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/HalApplicationProcessor.cpp b/src/kernel/HALKit/ARM64/HalApplicationProcessor.cpp new file mode 100644 index 00000000..33921a56 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalApplicationProcessor.cpp @@ -0,0 +1,138 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#define GICD_BASE 0x08000000 +#define GICC_BASE 0x08010000 + +#define GICD_CTLR 0x000 +#define GICD_ISENABLER 0x100 +#define GICD_ICENABLER 0x180 +#define GICD_ISPENDR 0x200 +#define GICD_ICPENDR 0x280 +#define GICD_IPRIORITYR 0x400 +#define GICD_ITARGETSR 0x800 +#define GICD_ICFGR 0xC00 + +#define GICC_CTLR 0x000 +#define GICC_PMR 0x004 +#define GICC_IAR 0x00C +#define GICC_EOIR 0x010 + +#include +#include +#include +#include +#include +#include + +// ================================================================= // + +namespace Kernel { +struct HAL_HARDWARE_THREAD final { + HAL::StackFramePtr mFramePtr; + ProcessID mThreadID{0}; +}; + +STATIC HAL_HARDWARE_THREAD kHWThread[kMaxAPInsideSched] = {{nullptr}}; + +namespace Detail { + STATIC BOOL kGICEnabled = NO; + + /***********************************************************************************/ + /// @brief Enables the GIC with EL0 configuration. + /// @internal + /***********************************************************************************/ + STATIC Void mp_setup_gic_el0(Void) { + ke_dma_write(GICD_BASE, GICD_CTLR, YES); + + UInt32 gicc_ctlr = ke_dma_read(GICC_BASE, GICC_CTLR); + + const UInt8 kEnableSignalInt = 0x1; + + gicc_ctlr |= kEnableSignalInt; + gicc_ctlr |= (kEnableSignalInt << 0x1); + + ke_dma_write(GICC_BASE, GICC_CTLR, gicc_ctlr); + + ke_dma_write(GICC_BASE, GICC_PMR, 0xFF); + + UInt32 icfgr = ke_dma_read(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4); + + icfgr |= (0x2 << ((32 % 16) * 2)); + + ke_dma_write(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4, icfgr); + ke_dma_write(GICD_BASE, GICD_ITARGETSR + (0x20 / 0x04) * 4, 0x2 << ((32 % 4) * 8)); + ke_dma_write(GICD_BASE, GICD_IPRIORITYR + (0x20 / 0x04) * 4, 0xFF << ((32 % 4) * 8)); + ke_dma_write(GICD_BASE, GICD_ISENABLER + 4, 0x01); + } + + EXTERN_C BOOL mp_handle_gic_interrupt_el0(Void) { + UInt32 interrupt_id = ke_dma_read(GICC_BASE, GICC_IAR); + + if ((interrupt_id & 0x3FF) < 1020) { + auto interrupt = interrupt_id & 0x3FF; + + const UInt16 kInterruptScheduler = 0x20; + + (Void)(kout << "SMP: AP: " << hex_number(interrupt) << kendl); + + switch (interrupt) { + case kInterruptScheduler: { + ke_dma_write(GICC_BASE, GICC_EOIR, interrupt_id); + UserProcessHelper::StartScheduling(); + break; + } + default: { + ke_dma_write(GICC_BASE, GICC_EOIR, interrupt_id); + break; + } + } + + return YES; + } + + return NO; + } +} // namespace Detail + +/***********************************************************************************/ +/// @brief Get current stack frame for a thread. +/// @param thrdid The thread ID. +/***********************************************************************************/ + +EXTERN_C HAL::StackFramePtr mp_get_current_task(ProcessID thrdid) { + return kHWThread[thrdid].mFramePtr; +} + +/***********************************************************************************/ +/// @brief Register current stack frame for a thread. +/// @param stack_frame The current stack frame. +/// @param thrdid The thread ID. +/***********************************************************************************/ + +EXTERN_C Bool mp_register_task(HAL::StackFramePtr stack_frame, ProcessID thrdid) { + MUST_PASS(Detail::kGICEnabled); + + if (!stack_frame) return NO; + if (thrdid > kMaxAPInsideSched) return NO; + + const auto process_index = thrdid; + + kHWThread[process_index].mFramePtr = stack_frame; + kHWThread[process_index].mThreadID = thrdid; + + return YES; +} + +/***********************************************************************************/ +/// @brief Initialize the Global Interrupt Controller. +/// @internal +/***********************************************************************************/ +Void mp_init_cores(Void) { + if (!Detail::kGICEnabled) { + Detail::kGICEnabled = YES; + Detail::mp_setup_gic_el0(); + } +} +} // namespace Kernel \ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc b/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc deleted file mode 100644 index f0085e13..00000000 --- a/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include - -EXTERN_C Kernel::Void int_handle_breakpoint(Kernel::UIntPtr rip); -EXTERN_C BOOL mp_handle_gic_interrupt_el0(Void); - -EXTERN_C BOOL kEndOfInterrupt; -EXTERN_C UInt8 kEndOfInterruptVector; - -STATIC BOOL kIsRunning = NO; - -/// @note This is managed by the system software. -STATIC void hal_int_send_eoi(UInt8 vector) { - kEndOfInterrupt = YES; - kEndOfInterruptVector = vector; -} - -/// @brief Handle GPF fault. -/// @param rsp -EXTERN_C Kernel::Void int_handle_gpf(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - process.Crash(); - - hal_int_send_eoi(13); - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; -} - -/// @brief Handle page fault. -/// @param rsp -EXTERN_C void int_handle_pf(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - process.Crash(); - - hal_int_send_eoi(14); - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; -} - -/// @brief Handle scheduler interrupt. -EXTERN_C void int_handle_scheduler(Kernel::UIntPtr rsp) { - NE_UNUSED(rsp); - - hal_int_send_eoi(32); - - while (kIsRunning); - - kIsRunning = YES; - - mp_handle_gic_interrupt_el0(); - - kIsRunning = NO; -} - -/// @brief Handle math fault. -/// @param rsp -EXTERN_C void int_handle_math(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - process.Crash(); - - hal_int_send_eoi(8); - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; -} - -/// @brief Handle any generic fault. -/// @param rsp -EXTERN_C void int_handle_generic(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - process.Crash(); - - hal_int_send_eoi(30); - - Kernel::kout << "Kernel: Generic Process Fault.\r"; - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; - - Kernel::kout << "Kernel: SIGKILL status.\r"; -} - -EXTERN_C Kernel::Void int_handle_breakpoint(Kernel::UIntPtr rip) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - - hal_int_send_eoi(3); - - process.Signal.SignalArg = rip; - process.Signal.SignalID = SIGTRAP; - - process.Signal.Status = process.Status; - - process.Status = Kernel::ProcessStatusKind::kFrozen; -} - -/// @brief Handle #UD fault. -/// @param rsp -EXTERN_C void int_handle_ud(Kernel::UIntPtr rsp) { - auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); - process.Crash(); - - hal_int_send_eoi(6); - - process.Signal.SignalArg = rsp; - process.Signal.SignalID = SIGKILL; - process.Signal.Status = process.Status; -} - -/// @brief Enter syscall from assembly (libSystem only) -/// @param stack the stack pushed from assembly routine. -/// @return nothing. -EXTERN_C Kernel::Void hal_system_call_enter(Kernel::UIntPtr rcx_hash, - Kernel::UIntPtr rdx_syscall_arg) { - hal_int_send_eoi(50); - - if (!Kernel::kCurrentUser) return; - - for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { - if (kSysCalls[i].fHooked && rcx_hash == kSysCalls[i].fHash) { - if (kSysCalls[i].fProc) { - (kSysCalls[i].fProc)((Kernel::VoidPtr) rdx_syscall_arg); - } - } - } -} - -/// @brief Enter Kernel call from assembly (libDDK only). -/// @param stack the stack pushed from assembly routine. -/// @return nothing. -EXTERN_C Kernel::Void hal_kernel_call_enter(Kernel::UIntPtr rcx_hash, Kernel::SizeT cnt, - Kernel::UIntPtr arg, Kernel::SizeT sz) { - if (!Kernel::kRootUser) return; - if (Kernel::kCurrentUser != Kernel::kRootUser) return; - if (!Kernel::kCurrentUser->IsSuperUser()) return; - - for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { - if (kKernCalls[i].fHooked && rcx_hash == kKernCalls[rcx_hash].fHash) { - if (kKernCalls[i].fProc) { - (kKernCalls[i].fProc)(cnt, (Kernel::VoidPtr) arg, sz); - } - } - } -} diff --git a/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cpp b/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cpp new file mode 100644 index 00000000..f0085e13 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cpp @@ -0,0 +1,156 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include + +EXTERN_C Kernel::Void int_handle_breakpoint(Kernel::UIntPtr rip); +EXTERN_C BOOL mp_handle_gic_interrupt_el0(Void); + +EXTERN_C BOOL kEndOfInterrupt; +EXTERN_C UInt8 kEndOfInterruptVector; + +STATIC BOOL kIsRunning = NO; + +/// @note This is managed by the system software. +STATIC void hal_int_send_eoi(UInt8 vector) { + kEndOfInterrupt = YES; + kEndOfInterruptVector = vector; +} + +/// @brief Handle GPF fault. +/// @param rsp +EXTERN_C Kernel::Void int_handle_gpf(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Crash(); + + hal_int_send_eoi(13); + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; +} + +/// @brief Handle page fault. +/// @param rsp +EXTERN_C void int_handle_pf(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Crash(); + + hal_int_send_eoi(14); + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; +} + +/// @brief Handle scheduler interrupt. +EXTERN_C void int_handle_scheduler(Kernel::UIntPtr rsp) { + NE_UNUSED(rsp); + + hal_int_send_eoi(32); + + while (kIsRunning); + + kIsRunning = YES; + + mp_handle_gic_interrupt_el0(); + + kIsRunning = NO; +} + +/// @brief Handle math fault. +/// @param rsp +EXTERN_C void int_handle_math(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Crash(); + + hal_int_send_eoi(8); + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; +} + +/// @brief Handle any generic fault. +/// @param rsp +EXTERN_C void int_handle_generic(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Crash(); + + hal_int_send_eoi(30); + + Kernel::kout << "Kernel: Generic Process Fault.\r"; + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; + + Kernel::kout << "Kernel: SIGKILL status.\r"; +} + +EXTERN_C Kernel::Void int_handle_breakpoint(Kernel::UIntPtr rip) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + + hal_int_send_eoi(3); + + process.Signal.SignalArg = rip; + process.Signal.SignalID = SIGTRAP; + + process.Signal.Status = process.Status; + + process.Status = Kernel::ProcessStatusKind::kFrozen; +} + +/// @brief Handle #UD fault. +/// @param rsp +EXTERN_C void int_handle_ud(Kernel::UIntPtr rsp) { + auto process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Crash(); + + hal_int_send_eoi(6); + + process.Signal.SignalArg = rsp; + process.Signal.SignalID = SIGKILL; + process.Signal.Status = process.Status; +} + +/// @brief Enter syscall from assembly (libSystem only) +/// @param stack the stack pushed from assembly routine. +/// @return nothing. +EXTERN_C Kernel::Void hal_system_call_enter(Kernel::UIntPtr rcx_hash, + Kernel::UIntPtr rdx_syscall_arg) { + hal_int_send_eoi(50); + + if (!Kernel::kCurrentUser) return; + + for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { + if (kSysCalls[i].fHooked && rcx_hash == kSysCalls[i].fHash) { + if (kSysCalls[i].fProc) { + (kSysCalls[i].fProc)((Kernel::VoidPtr) rdx_syscall_arg); + } + } + } +} + +/// @brief Enter Kernel call from assembly (libDDK only). +/// @param stack the stack pushed from assembly routine. +/// @return nothing. +EXTERN_C Kernel::Void hal_kernel_call_enter(Kernel::UIntPtr rcx_hash, Kernel::SizeT cnt, + Kernel::UIntPtr arg, Kernel::SizeT sz) { + if (!Kernel::kRootUser) return; + if (Kernel::kCurrentUser != Kernel::kRootUser) return; + if (!Kernel::kCurrentUser->IsSuperUser()) return; + + for (SizeT i = 0UL; i < kMaxDispatchCallCount; ++i) { + if (kKernCalls[i].fHooked && rcx_hash == kKernCalls[rcx_hash].fHash) { + if (kKernCalls[i].fProc) { + (kKernCalls[i].fProc)(cnt, (Kernel::VoidPtr) arg, sz); + } + } + } +} diff --git a/src/kernel/HALKit/ARM64/HalDebugOutput.cc b/src/kernel/HALKit/ARM64/HalDebugOutput.cc deleted file mode 100644 index 4e47d38e..00000000 --- a/src/kernel/HALKit/ARM64/HalDebugOutput.cc +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include - -namespace Kernel { -EXTERN_C void ke_io_write(IDevice* self, const Char* bytes) { -#ifdef __DEBUG__ - if (*bytes == 0) return; - - SizeT index = 0; - SizeT len = 0; - - index = 0; - len = rt_string_len(bytes, 256U); - - volatile UInt8* uart_ptr = (UInt8*) 0x09000000; - - while (index < len) { - if (bytes[index] == '\r') *uart_ptr = '\r'; - - *uart_ptr = bytes[index] == '\r' ? '\n' : bytes[index]; - ++index; - } -#endif // __DEBUG__ -} - -TerminalDevice::~TerminalDevice() = default; - -EXTERN_C void ke_io_read(IDevice* self, const Char* bytes) { -#ifdef __DEBUG__ - SizeT index = 0; - - volatile UInt8* uart_ptr = (UInt8*) 0x09000000; - - ///! TODO: Look on how to wait for the UART to complete. - while (Yes) { - auto in = *uart_ptr; - - ///! If enter pressed then break. - if (in == 0xD) { - break; - } - - if (in < '0' || in < 'A' || in < 'a') { - if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || in != ':') { - continue; - } - } - - ((char*) bytes)[index] = in; - - ++index; - } - - ((char*) bytes)[index] = 0; -#endif // __DEBUG__ -} - -TerminalDevice TerminalDevice::The() { - TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read); - return out; -} - -} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalDebugOutput.cpp b/src/kernel/HALKit/ARM64/HalDebugOutput.cpp new file mode 100644 index 00000000..4e47d38e --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalDebugOutput.cpp @@ -0,0 +1,69 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include + +namespace Kernel { +EXTERN_C void ke_io_write(IDevice* self, const Char* bytes) { +#ifdef __DEBUG__ + if (*bytes == 0) return; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = rt_string_len(bytes, 256U); + + volatile UInt8* uart_ptr = (UInt8*) 0x09000000; + + while (index < len) { + if (bytes[index] == '\r') *uart_ptr = '\r'; + + *uart_ptr = bytes[index] == '\r' ? '\n' : bytes[index]; + ++index; + } +#endif // __DEBUG__ +} + +TerminalDevice::~TerminalDevice() = default; + +EXTERN_C void ke_io_read(IDevice* self, const Char* bytes) { +#ifdef __DEBUG__ + SizeT index = 0; + + volatile UInt8* uart_ptr = (UInt8*) 0x09000000; + + ///! TODO: Look on how to wait for the UART to complete. + while (Yes) { + auto in = *uart_ptr; + + ///! If enter pressed then break. + if (in == 0xD) { + break; + } + + if (in < '0' || in < 'A' || in < 'a') { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || in != ':') { + continue; + } + } + + ((char*) bytes)[index] = in; + + ++index; + } + + ((char*) bytes)[index] = 0; +#endif // __DEBUG__ +} + +TerminalDevice TerminalDevice::The() { + TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read); + return out; +} + +} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalKernelMain.cc b/src/kernel/HALKit/ARM64/HalKernelMain.cc deleted file mode 100644 index 3a6e4085..00000000 --- a/src/kernel/HALKit/ARM64/HalKernelMain.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ -EXTERN_C void hal_init_platform(Kernel::HEL::BootInfoHeader* handover_hdr) { - using namespace Kernel; - - /************************************************** */ - /* INITIALIZE AND VALIDATE HEADER. */ - /************************************************** */ - - kHandoverHeader = handover_hdr; - - if (kHandoverHeader->f_Magic != kHandoverMagic && - kHandoverHeader->f_Version != kHandoverVersion) { - return; - } - -#ifdef __NE_ARM64_EFI__ - fw_init_efi((EfiSystemTable*) handover_hdr->f_FirmwareCustomTables[1]); - - Boot::ExitBootServices(handover_hdr->f_HardwareTables.f_ImageKey, - handover_hdr->f_HardwareTables.f_ImageHandle); -#endif - - FB::cg_clear_video(); - - /************************************** */ - /* INITIALIZE BIT MAP. */ - /************************************** */ - - kBitMapCursor = 0UL; - kKernelBitMpSize = kHandoverHeader->f_BitMapSize; - kKernelBitMpStart = reinterpret_cast( - reinterpret_cast(kHandoverHeader->f_BitMapStart)); - - /// @note do initialize the interrupts after it. - - Kernel::mp_init_cores(); - - while (YES); -} -#endif diff --git a/src/kernel/HALKit/ARM64/HalKernelMain.cpp b/src/kernel/HALKit/ARM64/HalKernelMain.cpp new file mode 100644 index 00000000..3a6e4085 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalKernelMain.cpp @@ -0,0 +1,60 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __NE_MODULAR_KERNEL_COMPONENTS__ +EXTERN_C void hal_init_platform(Kernel::HEL::BootInfoHeader* handover_hdr) { + using namespace Kernel; + + /************************************************** */ + /* INITIALIZE AND VALIDATE HEADER. */ + /************************************************** */ + + kHandoverHeader = handover_hdr; + + if (kHandoverHeader->f_Magic != kHandoverMagic && + kHandoverHeader->f_Version != kHandoverVersion) { + return; + } + +#ifdef __NE_ARM64_EFI__ + fw_init_efi((EfiSystemTable*) handover_hdr->f_FirmwareCustomTables[1]); + + Boot::ExitBootServices(handover_hdr->f_HardwareTables.f_ImageKey, + handover_hdr->f_HardwareTables.f_ImageHandle); +#endif + + FB::cg_clear_video(); + + /************************************** */ + /* INITIALIZE BIT MAP. */ + /************************************** */ + + kBitMapCursor = 0UL; + kKernelBitMpSize = kHandoverHeader->f_BitMapSize; + kKernelBitMpStart = reinterpret_cast( + reinterpret_cast(kHandoverHeader->f_BitMapStart)); + + /// @note do initialize the interrupts after it. + + Kernel::mp_init_cores(); + + while (YES); +} +#endif diff --git a/src/kernel/HALKit/ARM64/HalKernelPanic.cc b/src/kernel/HALKit/ARM64/HalKernelPanic.cc deleted file mode 100644 index 59397611..00000000 --- a/src/kernel/HALKit/ARM64/HalKernelPanic.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Each error code is attributed with an ID, which will prompt a string onto the - * screen. Wait for debugger... */ - -namespace Kernel { -/// @brief Dumping factory class. -class RecoveryFactory final { - public: - STATIC Void Recover(); -}; - -/***********************************************************************************/ -/// @brief Stops execution of the kernel. -/// @param id kernel stop ID. -/***********************************************************************************/ -Void ke_panic(const Kernel::Int32& id, const Char* message) { - (Void)(kout << "*** STOP ***\r"); - (Void)(kout << "Kernel_Panic_MSG: " << message << kendl); - (Void)(kout << "Kernel_Panic_ID: " << hex_number(id) << kendl); - - RecoveryFactory::Recover(); -} - -Void RecoveryFactory::Recover() { - while (YES) { - HAL::rt_halt(); - } -} - -void ke_runtime_check(bool expr, const Char* file, const Char* line) { - if (!expr) { - (Void)(kout << "Kernel_Panic_FILE: " << file << kendl); - (Void)(kout << "Kernel_Panic_LINE: " << line << kendl); - - ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed - } -} -} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalKernelPanic.cpp b/src/kernel/HALKit/ARM64/HalKernelPanic.cpp new file mode 100644 index 00000000..59397611 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalKernelPanic.cpp @@ -0,0 +1,52 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Each error code is attributed with an ID, which will prompt a string onto the + * screen. Wait for debugger... */ + +namespace Kernel { +/// @brief Dumping factory class. +class RecoveryFactory final { + public: + STATIC Void Recover(); +}; + +/***********************************************************************************/ +/// @brief Stops execution of the kernel. +/// @param id kernel stop ID. +/***********************************************************************************/ +Void ke_panic(const Kernel::Int32& id, const Char* message) { + (Void)(kout << "*** STOP ***\r"); + (Void)(kout << "Kernel_Panic_MSG: " << message << kendl); + (Void)(kout << "Kernel_Panic_ID: " << hex_number(id) << kendl); + + RecoveryFactory::Recover(); +} + +Void RecoveryFactory::Recover() { + while (YES) { + HAL::rt_halt(); + } +} + +void ke_runtime_check(bool expr, const Char* file, const Char* line) { + if (!expr) { + (Void)(kout << "Kernel_Panic_FILE: " << file << kendl); + (Void)(kout << "Kernel_Panic_LINE: " << line << kendl); + + ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed + } +} +} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalPagingMgr.cc b/src/kernel/HALKit/ARM64/HalPagingMgr.cc deleted file mode 100644 index 0fe4d759..00000000 --- a/src/kernel/HALKit/ARM64/HalPagingMgr.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -namespace Kernel::HAL { -typedef UInt32 PageTableIndex; - -EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virtual_address) { - if (!virtual_address) return 0; - - UInt64 ttbr0_val = 0; - - asm volatile("mrs %0, ttbr0_el1" : "=r"(ttbr0_val)); - volatile UInt64* l1_table = reinterpret_cast(ttbr0_val); - - UInt64 l1_idx = (reinterpret_cast(virtual_address) >> 39) & 0x1FF; - UInt64 l2_idx = (reinterpret_cast(virtual_address) >> 30) & 0x1FF; - UInt64 l3_idx = (reinterpret_cast(virtual_address) >> 21) & 0x1FF; - - if (!l1_table[l1_idx]) return 0; - - volatile UInt64* l2_table = reinterpret_cast(l1_table[l1_idx] & ~0xFFFUL); - - if (!l2_table[l2_idx]) return 0; - - volatile UInt64* l3_table = reinterpret_cast(l2_table[l2_idx] & ~0xFFFUL); - - if (!l3_table[l3_idx]) return 0; - - return (l3_table[l3_idx] & ~0xFFFUL); -} - -/// @brief Maps or allocates a page from virtual_address. -/// @param virtual_address a valid virtual address. -/// @param phys_addr point to physical address. -/// @param flags the flags to put on the page. -/// @return Status code of page manipulation process. -EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, - UInt32 level) { - if (!virtual_address || !flags || !physical_address) return kErrorInvalidData; - - UInt64 ttbr0_val = 0; - - asm volatile("mrs %0, ttbr0_el1" : "=r"(ttbr0_val)); - volatile UInt64* l1_table = reinterpret_cast(ttbr0_val); - - UInt64 l1_idx = (reinterpret_cast(virtual_address) >> 39) & 0x1FF; - UInt64 l2_idx = (reinterpret_cast(virtual_address) >> 30) & 0x1FF; - UInt64 l3_idx = (reinterpret_cast(virtual_address) >> 21) & 0x1FF; - - if (!l1_table[l1_idx]) return kErrorInvalidData; - - volatile UInt64* l2_table = reinterpret_cast(l1_table[l1_idx] & ~0xFFFUL); - - if (!l2_table[l2_idx]) return kErrorInvalidData; - - volatile UInt64* l3_table = reinterpret_cast(l2_table[l2_idx] & ~0xFFFUL); - - l3_table[l3_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; - - switch (level) { - case 2: { - l3_table[l3_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; - return kErrorSuccess; - } - case 1: { - l1_table[l1_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; - return kErrorSuccess; - } - case 0: { - l1_table[l1_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; - return kErrorSuccess; - } - } - - return kErrorInvalidData; -} -} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/ARM64/HalPagingMgr.cpp b/src/kernel/HALKit/ARM64/HalPagingMgr.cpp new file mode 100644 index 00000000..0fe4d759 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalPagingMgr.cpp @@ -0,0 +1,81 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +namespace Kernel::HAL { +typedef UInt32 PageTableIndex; + +EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virtual_address) { + if (!virtual_address) return 0; + + UInt64 ttbr0_val = 0; + + asm volatile("mrs %0, ttbr0_el1" : "=r"(ttbr0_val)); + volatile UInt64* l1_table = reinterpret_cast(ttbr0_val); + + UInt64 l1_idx = (reinterpret_cast(virtual_address) >> 39) & 0x1FF; + UInt64 l2_idx = (reinterpret_cast(virtual_address) >> 30) & 0x1FF; + UInt64 l3_idx = (reinterpret_cast(virtual_address) >> 21) & 0x1FF; + + if (!l1_table[l1_idx]) return 0; + + volatile UInt64* l2_table = reinterpret_cast(l1_table[l1_idx] & ~0xFFFUL); + + if (!l2_table[l2_idx]) return 0; + + volatile UInt64* l3_table = reinterpret_cast(l2_table[l2_idx] & ~0xFFFUL); + + if (!l3_table[l3_idx]) return 0; + + return (l3_table[l3_idx] & ~0xFFFUL); +} + +/// @brief Maps or allocates a page from virtual_address. +/// @param virtual_address a valid virtual address. +/// @param phys_addr point to physical address. +/// @param flags the flags to put on the page. +/// @return Status code of page manipulation process. +EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, + UInt32 level) { + if (!virtual_address || !flags || !physical_address) return kErrorInvalidData; + + UInt64 ttbr0_val = 0; + + asm volatile("mrs %0, ttbr0_el1" : "=r"(ttbr0_val)); + volatile UInt64* l1_table = reinterpret_cast(ttbr0_val); + + UInt64 l1_idx = (reinterpret_cast(virtual_address) >> 39) & 0x1FF; + UInt64 l2_idx = (reinterpret_cast(virtual_address) >> 30) & 0x1FF; + UInt64 l3_idx = (reinterpret_cast(virtual_address) >> 21) & 0x1FF; + + if (!l1_table[l1_idx]) return kErrorInvalidData; + + volatile UInt64* l2_table = reinterpret_cast(l1_table[l1_idx] & ~0xFFFUL); + + if (!l2_table[l2_idx]) return kErrorInvalidData; + + volatile UInt64* l3_table = reinterpret_cast(l2_table[l2_idx] & ~0xFFFUL); + + l3_table[l3_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; + + switch (level) { + case 2: { + l3_table[l3_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; + return kErrorSuccess; + } + case 1: { + l1_table[l1_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; + return kErrorSuccess; + } + case 0: { + l1_table[l1_idx] = (reinterpret_cast(physical_address) & ~0xFFFUL) | flags; + return kErrorSuccess; + } + } + + return kErrorInvalidData; +} +} // namespace Kernel::HAL diff --git a/src/kernel/HALKit/ARM64/HalSchedulerCore.cc b/src/kernel/HALKit/ARM64/HalSchedulerCore.cc deleted file mode 100644 index ecf666e8..00000000 --- a/src/kernel/HALKit/ARM64/HalSchedulerCore.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -namespace Kernel { -/// @brief Wakes up thread. -/// Wakes up thread from the hang state. -Void mp_wakeup_thread(HAL::StackFrame* stack) { - NE_UNUSED(stack); -} - -/// @brief makes the thread sleep on a loop. -/// hooks and hangs thread to prevent code from executing. -Void mp_hang_thread(HAL::StackFrame* stack) { - NE_UNUSED(stack); -} -} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalSchedulerCore.cpp b/src/kernel/HALKit/ARM64/HalSchedulerCore.cpp new file mode 100644 index 00000000..ecf666e8 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalSchedulerCore.cpp @@ -0,0 +1,19 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +namespace Kernel { +/// @brief Wakes up thread. +/// Wakes up thread from the hang state. +Void mp_wakeup_thread(HAL::StackFrame* stack) { + NE_UNUSED(stack); +} + +/// @brief makes the thread sleep on a loop. +/// hooks and hangs thread to prevent code from executing. +Void mp_hang_thread(HAL::StackFrame* stack) { + NE_UNUSED(stack); +} +} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cc b/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cc deleted file mode 100644 index 960dbc6d..00000000 --- a/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -namespace Kernel { -/***********************************************************************************/ -/// @brief Unimplemented function (crashes by default) -/// @param process The process handle. -/***********************************************************************************/ - -EXTERN_C Void __ne_pure_call(UserProcess* process) { - if (process) process->Crash(); -} - -/***********************************************************************************/ -/// @brief Validate user stack. -/// @param stack_ptr the frame pointer. -/***********************************************************************************/ - -EXTERN_C Bool hal_check_task(HAL::StackFramePtr stack_ptr) { - if (!stack_ptr) return No; - - return stack_ptr->SP != 0 && stack_ptr->IP != 0; -} -} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cpp b/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cpp new file mode 100644 index 00000000..960dbc6d --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cpp @@ -0,0 +1,28 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +namespace Kernel { +/***********************************************************************************/ +/// @brief Unimplemented function (crashes by default) +/// @param process The process handle. +/***********************************************************************************/ + +EXTERN_C Void __ne_pure_call(UserProcess* process) { + if (process) process->Crash(); +} + +/***********************************************************************************/ +/// @brief Validate user stack. +/// @param stack_ptr the frame pointer. +/***********************************************************************************/ + +EXTERN_C Bool hal_check_task(HAL::StackFramePtr stack_ptr) { + if (!stack_ptr) return No; + + return stack_ptr->SP != 0 && stack_ptr->IP != 0; +} +} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalTimer.cc b/src/kernel/HALKit/ARM64/HalTimer.cc deleted file mode 100644 index 3084838d..00000000 --- a/src/kernel/HALKit/ARM64/HalTimer.cc +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include \ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/HalTimer.cpp b/src/kernel/HALKit/ARM64/HalTimer.cpp new file mode 100644 index 00000000..3084838d --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalTimer.cpp @@ -0,0 +1,6 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include \ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cc b/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cc deleted file mode 100644 index f73946d7..00000000 --- a/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cc +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include - -using namespace Kernel; - -///! @brief ATAPI SCSI packet. -const ATTRIBUTE(unused) scsi_packet_type_12 kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, - 0, 12, 0x40, 0, 0}; diff --git a/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cpp b/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cpp new file mode 100644 index 00000000..f73946d7 --- /dev/null +++ b/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cpp @@ -0,0 +1,11 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include + +using namespace Kernel; + +///! @brief ATAPI SCSI packet. +const ATTRIBUTE(unused) scsi_packet_type_12 kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, + 0, 12, 0x40, 0, 0}; diff --git a/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cc b/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cc deleted file mode 100644 index ba8d285b..00000000 --- a/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cc +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel diff --git a/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cpp b/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cpp new file mode 100644 index 00000000..ba8d285b --- /dev/null +++ b/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cpp @@ -0,0 +1,3 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel diff --git a/src/kernel/HALKit/POWER/HalApplicationProcessor.cc b/src/kernel/HALKit/POWER/HalApplicationProcessor.cc deleted file mode 100644 index 64333086..00000000 --- a/src/kernel/HALKit/POWER/HalApplicationProcessor.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -/// @note This part of the HAL needs an owner. - -namespace Kernel::Detail { -STATIC void mp_hang_fn(void) { - while (YES); -} -} // namespace Kernel::Detail - -namespace Kernel { -/// @brief wakes up thread. -/// wakes up thread from hang. -void mp_wakeup_thread(HAL::StackFramePtr stack) { - if (!stack) return; - - MUST_PASS(stack->R15 > 0); - MUST_PASS(stack->IP > 0); - - hal_set_pc_to_hart(reinterpret_cast(stack->R15), - reinterpret_cast(stack->IP)); -} - -/// @brief makes thread sleep. -/// hooks and hangs thread to prevent code from executing. -void mp_hang_thread(HAL::StackFramePtr stack) { - if (!stack) return; - - MUST_PASS(stack->R15 > 0); - - hal_set_pc_to_hart(reinterpret_cast(stack->R15), - reinterpret_cast(Kernel::Detail::mp_hang_fn)); -} -} // namespace Kernel diff --git a/src/kernel/HALKit/POWER/HalApplicationProcessor.cpp b/src/kernel/HALKit/POWER/HalApplicationProcessor.cpp new file mode 100644 index 00000000..64333086 --- /dev/null +++ b/src/kernel/HALKit/POWER/HalApplicationProcessor.cpp @@ -0,0 +1,40 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +/// @note This part of the HAL needs an owner. + +namespace Kernel::Detail { +STATIC void mp_hang_fn(void) { + while (YES); +} +} // namespace Kernel::Detail + +namespace Kernel { +/// @brief wakes up thread. +/// wakes up thread from hang. +void mp_wakeup_thread(HAL::StackFramePtr stack) { + if (!stack) return; + + MUST_PASS(stack->R15 > 0); + MUST_PASS(stack->IP > 0); + + hal_set_pc_to_hart(reinterpret_cast(stack->R15), + reinterpret_cast(stack->IP)); +} + +/// @brief makes thread sleep. +/// hooks and hangs thread to prevent code from executing. +void mp_hang_thread(HAL::StackFramePtr stack) { + if (!stack) return; + + MUST_PASS(stack->R15 > 0); + + hal_set_pc_to_hart(reinterpret_cast(stack->R15), + reinterpret_cast(Kernel::Detail::mp_hang_fn)); +} +} // namespace Kernel diff --git a/src/kernel/HALKit/POWER/HalDebugOutput.cc b/src/kernel/HALKit/POWER/HalDebugOutput.cc deleted file mode 100644 index c43e575d..00000000 --- a/src/kernel/HALKit/POWER/HalDebugOutput.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include - -using namespace Kernel; - -/// @brief Writes to COM1. -/// @param bytes -void ke_io_write(const Char* bytes) { - if (!bytes) return; - - SizeT index = 0; - SizeT len = rt_string_len(bytes, 256U); - - while (index < len) { - // TODO - ++index; - } -} diff --git a/src/kernel/HALKit/POWER/HalDebugOutput.cpp b/src/kernel/HALKit/POWER/HalDebugOutput.cpp new file mode 100644 index 00000000..c43e575d --- /dev/null +++ b/src/kernel/HALKit/POWER/HalDebugOutput.cpp @@ -0,0 +1,22 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include + +using namespace Kernel; + +/// @brief Writes to COM1. +/// @param bytes +void ke_io_write(const Char* bytes) { + if (!bytes) return; + + SizeT index = 0; + SizeT len = rt_string_len(bytes, 256U); + + while (index < len) { + // TODO + ++index; + } +} diff --git a/src/kernel/HALKit/POWER/HalHardwareThread.cc b/src/kernel/HALKit/POWER/HalHardwareThread.cc deleted file mode 100644 index fff5b68b..00000000 --- a/src/kernel/HALKit/POWER/HalHardwareThread.cc +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include diff --git a/src/kernel/HALKit/POWER/HalHardwareThread.cpp b/src/kernel/HALKit/POWER/HalHardwareThread.cpp new file mode 100644 index 00000000..fff5b68b --- /dev/null +++ b/src/kernel/HALKit/POWER/HalHardwareThread.cpp @@ -0,0 +1,6 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include diff --git a/src/kernel/HALKit/POWER/HalVirtualMemory.cc b/src/kernel/HALKit/POWER/HalVirtualMemory.cc deleted file mode 100644 index 0c954f29..00000000 --- a/src/kernel/HALKit/POWER/HalVirtualMemory.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -/// @note Refer to SoC documentation. - -using namespace Kernel; - -EXTERN_C Void hal_write_tlb(UInt32 mas0, UInt32 mas1, UInt32 mas2, UInt32 mas3, UInt32 mas7) { - hal_mtspr(MAS0, mas0); - hal_mtspr(MAS1, mas1); - hal_mtspr(MAS2, mas2); - hal_mtspr(MAS3, mas3); - hal_mtspr(MAS7, mas7); - - hal_flush_tlb(); -} - -EXTERN_C Bool hal_set_tlb(UInt8 tlb, UInt32 epn, UInt64 rpn, UInt8 perms, UInt8 wimge, UInt8 ts, - UInt8 esel, UInt8 tsize, UInt8 iprot) { - if ((hal_mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 && (tsize & 1)) { - // this MMU does not allow odd tsize values - return false; - } - - UInt32 mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); - UInt32 mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); - UInt32 mas2 = FSL_BOOKE_MAS2(epn, wimge); - UInt32 mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); - UInt32 mas7 = FSL_BOOKE_MAS7(rpn); - - hal_write_tlb(mas0, mas1, mas2, mas3, mas7); - - return true; -} - -/// @brief Flush TLB -EXTERN_C void hal_flush_tlb() { - asm volatile("isync;tlbwe;msync;isync"); -} diff --git a/src/kernel/HALKit/POWER/HalVirtualMemory.cpp b/src/kernel/HALKit/POWER/HalVirtualMemory.cpp new file mode 100644 index 00000000..0c954f29 --- /dev/null +++ b/src/kernel/HALKit/POWER/HalVirtualMemory.cpp @@ -0,0 +1,44 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +/// @note Refer to SoC documentation. + +using namespace Kernel; + +EXTERN_C Void hal_write_tlb(UInt32 mas0, UInt32 mas1, UInt32 mas2, UInt32 mas3, UInt32 mas7) { + hal_mtspr(MAS0, mas0); + hal_mtspr(MAS1, mas1); + hal_mtspr(MAS2, mas2); + hal_mtspr(MAS3, mas3); + hal_mtspr(MAS7, mas7); + + hal_flush_tlb(); +} + +EXTERN_C Bool hal_set_tlb(UInt8 tlb, UInt32 epn, UInt64 rpn, UInt8 perms, UInt8 wimge, UInt8 ts, + UInt8 esel, UInt8 tsize, UInt8 iprot) { + if ((hal_mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 && (tsize & 1)) { + // this MMU does not allow odd tsize values + return false; + } + + UInt32 mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); + UInt32 mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); + UInt32 mas2 = FSL_BOOKE_MAS2(epn, wimge); + UInt32 mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); + UInt32 mas7 = FSL_BOOKE_MAS7(rpn); + + hal_write_tlb(mas0, mas1, mas2, mas3, mas7); + + return true; +} + +/// @brief Flush TLB +EXTERN_C void hal_flush_tlb() { + asm volatile("isync;tlbwe;msync;isync"); +} diff --git a/src/kernel/HALKit/RISCV/HalApplicationProcessor.cc b/src/kernel/HALKit/RISCV/HalApplicationProcessor.cc deleted file mode 100644 index 68242f97..00000000 --- a/src/kernel/HALKit/RISCV/HalApplicationProcessor.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) -// Licensed under the Apache License, Version 2.0 (see LICENSE file) -// Official repository: https://github.com/nekernel-org/nekernel - -#include -#include -#include - -using namespace Kernel; - -namespace Kernel { -namespace Detail { - STATIC void mp_hang_fn(void) { - while (YES); - } - -} // namespace Detail - -/// @brief wakes up thread. -/// wakes up thread from hang. -void mp_wakeup_thread(HAL::StackFramePtr stack) { - if (!stack) return; - - hal_set_pc_to_hart(reinterpret_cast(stack->R15), - reinterpret_cast(stack->IP)); -} - -/// @brief makes thread sleep. -/// hooks and hangs thread to prevent code from executing. -void mp_hang_thread(HAL::StackFramePtr stack) { - if (!stack) return; - - hal_set_pc_to_hart(reinterpret_cast(stack->R15), - reinterpret_cast(Kernel::Detail::mp_hang_fn)); -} - -} // namespace Kernel diff --git a/src/kernel/HALKit/RISCV/HalApplicationProcessor.cpp b/src/kernel/HALKit/RISCV/HalApplicationProcessor.cpp new file mode 100644 index 00000000..68242f97 --- /dev/null +++ b/src/kernel/HALKit/RISCV/HalApplicationProcessor.cpp @@ -0,0 +1,37 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include +#include +#include + +using namespace Kernel; + +namespace Kernel { +namespace Detail { + STATIC void mp_hang_fn(void) { + while (YES); + } + +} // namespace Detail + +/// @brief wakes up thread. +/// wakes up thread from hang. +void mp_wakeup_thread(HAL::StackFramePtr stack) { + if (!stack) return; + + hal_set_pc_to_hart(reinterpret_cast(stack->R15), + reinterpret_cast(stack->IP)); +} + +/// @brief makes thread sleep. +/// hooks and hangs thread to prevent code from executing. +void mp_hang_thread(HAL::StackFramePtr stack) { + if (!stack) return; + + hal_set_pc_to_hart(reinterpret_cast(stack->R15), + reinterpret_cast(Kernel::Detail::mp_hang_fn)); +} + +} // namespace Kernel -- cgit v1.2.3