diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-23 21:06:27 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-23 21:06:27 -0500 |
| commit | 23040fad647634c08697451fc22ee2ca999629c8 (patch) | |
| tree | 72888f88c7728c82f3f6df1f4f70591de15eab36 /src/kernel/HALKit/ARM64 | |
| parent | e5cc7351f0577b54c528fb827a7c7e6306c3e843 (diff) | |
| parent | 83d870e58457a1d335a1d9b9966a6a1887cc297b (diff) | |
Merge pull request #81 from nekernel-org/dev
feat! breaking changes on kernel sources.
Diffstat (limited to 'src/kernel/HALKit/ARM64')
21 files changed, 1055 insertions, 0 deletions
diff --git a/src/kernel/HALKit/ARM64/APM/APM+IO.cc b/src/kernel/HALKit/ARM64/APM/APM+IO.cc new file mode 100644 index 00000000..c4d0154b --- /dev/null +++ b/src/kernel/HALKit/ARM64/APM/APM+IO.cc @@ -0,0 +1,35 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <KernelKit/KPC.h> +#include <modules/APM/APM.h> + +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/ApplicationProcessor.h b/src/kernel/HALKit/ARM64/ApplicationProcessor.h new file mode 100644 index 00000000..208bf82e --- /dev/null +++ b/src/kernel/HALKit/ARM64/ApplicationProcessor.h @@ -0,0 +1,19 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <HALKit/ARM64/Processor.h> +#include <NeKit/Defines.h> + +/************************************************** */ +/* INITIALIZE THE GIC ON THE CURRENT CORE. */ +/* WITH AN EXECUTION LEVEL IN MIND. */ +/************************************************** */ + +namespace Kernel { +Void mp_init_cores(Void) noexcept; +}
\ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/CxxAbi.cc b/src/kernel/HALKit/ARM64/CxxAbi.cc new file mode 100644 index 00000000..7b4eca20 --- /dev/null +++ b/src/kernel/HALKit/ARM64/CxxAbi.cc @@ -0,0 +1,87 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/KPC.h> +#include <NeKit/CxxAbi.h> + +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<Kernel::UIntPtr>(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 new file mode 100644 index 00000000..9a8661cd --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc @@ -0,0 +1,26 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/HeapMgr.h> +#include <NeKit/KString.h> +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <modules/APM/APM.h> + +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 new file mode 100644 index 00000000..2a3c73e5 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalApplicationProcessor.cc @@ -0,0 +1,140 @@ +/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#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 <HALKit/ARM64/ApplicationProcessor.h>
+#include <HALKit/ARM64/Processor.h>
+#include <KernelKit/DebugOutput.h>
+#include <KernelKit/HardwareThreadScheduler.h>
+#include <KernelKit/ProcessScheduler.h>
+#include <KernelKit/Timer.h>
+
+// ================================================================= //
+
+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<UInt32>(GICD_BASE, GICD_CTLR, YES);
+
+ UInt32 gicc_ctlr = ke_dma_read<UInt32>(GICC_BASE, GICC_CTLR);
+
+ const UInt8 kEnableSignalInt = 0x1;
+
+ gicc_ctlr |= kEnableSignalInt;
+ gicc_ctlr |= (kEnableSignalInt << 0x1);
+
+ ke_dma_write<UInt32>(GICC_BASE, GICC_CTLR, gicc_ctlr);
+
+ ke_dma_write<UInt32>(GICC_BASE, GICC_PMR, 0xFF);
+
+ UInt32 icfgr = ke_dma_read<UInt32>(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4);
+
+ icfgr |= (0x2 << ((32 % 16) * 2));
+
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4, icfgr);
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ITARGETSR + (0x20 / 0x04) * 4, 0x2 << ((32 % 4) * 8));
+ ke_dma_write<UInt32>(GICD_BASE, GICD_IPRIORITYR + (0x20 / 0x04) * 4, 0xFF << ((32 % 4) * 8));
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ISENABLER + 4, 0x01);
+ }
+
+ EXTERN_C BOOL mp_handle_gic_interrupt_el0(Void) {
+ UInt32 interrupt_id = ke_dma_read<UInt32>(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<UInt32>(GICC_BASE, GICC_EOIR, interrupt_id);
+ UserProcessHelper::StartScheduling();
+ break;
+ }
+ default: {
+ ke_dma_write<UInt32>(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) noexcept {
+ 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/HalApplicationProcessorStartup.s b/src/kernel/HALKit/ARM64/HalApplicationProcessorStartup.s new file mode 100644 index 00000000..dca52571 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalApplicationProcessorStartup.s @@ -0,0 +1,12 @@ +.text + +.global hal_ap_blob_start +.global hal_ap_blob_length + +hal_ap_blob_start: + ret + +.data + +hal_ap_blob_length: + .long 4 diff --git a/src/kernel/HALKit/ARM64/HalCommonAPI.s b/src/kernel/HALKit/ARM64/HalCommonAPI.s new file mode 100644 index 00000000..f0c69368 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalCommonAPI.s @@ -0,0 +1,9 @@ +/* (c) 2024-2025 Amlal El Mahrouss */ + +.text + +.global hal_flush_tlb + +hal_flush_tlb: + tlbi vmalle1 + ret diff --git a/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc b/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc new file mode 100644 index 00000000..b89f68bd --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc @@ -0,0 +1,159 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/ProcessScheduler.h> +#include <KernelKit/UserMgr.h> +#include <NeKit/KString.h> +#include <SignalKit/Signals.h> + +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.Leak().Crash(); + + hal_int_send_eoi(13); + + process.Leak().Signal.SignalArg = rsp; + process.Leak().Signal.SignalID = SIGKILL; + process.Leak().Signal.Status = process.Leak().Status; +} + +/// @brief Handle page fault. +/// @param rsp +EXTERN_C void int_handle_pf(Kernel::UIntPtr rsp) { + auto& process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Leak().Crash(); + + hal_int_send_eoi(14); + + process.Leak().Signal.SignalArg = rsp; + process.Leak().Signal.SignalID = SIGKILL; + process.Leak().Signal.Status = process.Leak().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.Leak().Crash(); + + hal_int_send_eoi(8); + + process.Leak().Signal.SignalArg = rsp; + process.Leak().Signal.SignalID = SIGKILL; + process.Leak().Signal.Status = process.Leak().Status; +} + +/// @brief Handle any generic fault. +/// @param rsp +EXTERN_C void int_handle_generic(Kernel::UIntPtr rsp) { + auto& process = Kernel::UserProcessScheduler::The().TheCurrentProcess(); + process.Leak().Crash(); + + hal_int_send_eoi(30); + + Kernel::kout << "Kernel: Generic Process Fault.\r"; + + process.Leak().Signal.SignalArg = rsp; + process.Leak().Signal.SignalID = SIGKILL; + process.Leak().Signal.Status = process.Leak().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.Leak().Signal.SignalArg = rip; + process.Leak().Signal.SignalID = SIGTRAP; + + process.Leak().Signal.Status = process.Leak().Status; + + process.Leak().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.Leak().Crash(); + + hal_int_send_eoi(6); + + process.Leak().Signal.SignalArg = rsp; + process.Leak().Signal.SignalID = SIGKILL; + process.Leak().Signal.Status = process.Leak().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 new file mode 100644 index 00000000..c0da9c3a --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalDebugOutput.cc @@ -0,0 +1,71 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/DebugOutput.h> +#include <NeKit/New.h> +#include <NeKit/Utils.h> + +namespace Kernel { +EXTERN_C void ke_io_write(DeviceInterface<const Char*>* 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(DeviceInterface<const Char*>* 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() noexcept { + TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read); + return out; +} + +} // namespace Kernel diff --git a/src/kernel/HALKit/ARM64/HalHandoverStub.s b/src/kernel/HALKit/ARM64/HalHandoverStub.s new file mode 100644 index 00000000..5d5647c4 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalHandoverStub.s @@ -0,0 +1,19 @@ +;; /* +;; * ======================================================== +;; * +;; * NeKernel +;; * Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. +;; * +;; * ======================================================== +;; */ + +.section .ldr + + ;; // MAGIC +.quad 0xDAB4 + ;; // VERSION (1.0.0) +.word 100 + ;; // CPU (ARM64) +.word 0 + ;; // TYPE (KERNEL) +.word 122 diff --git a/src/kernel/HALKit/ARM64/HalInterruptAPI.s b/src/kernel/HALKit/ARM64/HalInterruptAPI.s new file mode 100644 index 00000000..cafebb7d --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalInterruptAPI.s @@ -0,0 +1,3 @@ +/* (c) 2024-2025 Amlal El Mahrouss */ + +.text diff --git a/src/kernel/HALKit/ARM64/HalKernelMain.cc b/src/kernel/HALKit/ARM64/HalKernelMain.cc new file mode 100644 index 00000000..e36535c3 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalKernelMain.cc @@ -0,0 +1,63 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <ArchKit/ArchKit.h> +#include <CFKit/Property.h> +#include <FirmwareKit/Handover.h> +#include <HALKit/ARM64/ApplicationProcessor.h> +#include <HALKit/ARM64/Processor.h> +#include <KernelKit/CodeMgr.h> +#include <KernelKit/FileMgr.h> +#include <KernelKit/HardwareThreadScheduler.h> +#include <KernelKit/HeapMgr.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/ProcessScheduler.h> +#include <NeKit/Json.h> +#include <NetworkKit/IPC.h> +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <modules/CoreGfx/CoreGfx.h> + +#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<Kernel::VoidPtr>( + reinterpret_cast<Kernel::UIntPtr>(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 new file mode 100644 index 00000000..6837ba1c --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalKernelPanic.cc @@ -0,0 +1,54 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <ArchKit/ArchKit.h> +#include <FirmwareKit/Handover.h> +#include <KernelKit/DebugOutput.h> +#include <KernelKit/FileMgr.h> +#include <KernelKit/Timer.h> +#include <NeKit/KString.h> +#include <NeKit/KernelPanic.h> +#include <NeKit/Utils.h> +#include <modules/CoreGfx/CoreGfx.h> +#include <modules/CoreGfx/TextGfx.h> + +/* 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() noexcept; +}; + +/***********************************************************************************/ +/// @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() noexcept { + 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 new file mode 100644 index 00000000..d597ccce --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalPagingMgr.cc @@ -0,0 +1,86 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: HalPagingMgr.cc + Purpose: Platform Paging Manager. + +======================================== */ + +#include <HALKit/ARM64/Paging.h> +#include <HALKit/ARM64/Processor.h> + +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<volatile UInt64*>(ttbr0_val); + + UInt64 l1_idx = (reinterpret_cast<UIntPtr>(virtual_address) >> 39) & 0x1FF; + UInt64 l2_idx = (reinterpret_cast<UIntPtr>(virtual_address) >> 30) & 0x1FF; + UInt64 l3_idx = (reinterpret_cast<UIntPtr>(virtual_address) >> 21) & 0x1FF; + + if (!l1_table[l1_idx]) return 0; + + volatile UInt64* l2_table = reinterpret_cast<volatile UInt64*>(l1_table[l1_idx] & ~0xFFFUL); + + if (!l2_table[l2_idx]) return 0; + + volatile UInt64* l3_table = reinterpret_cast<volatile UInt64*>(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<volatile UInt64*>(ttbr0_val); + + UInt64 l1_idx = (reinterpret_cast<UIntPtr>(virtual_address) >> 39) & 0x1FF; + UInt64 l2_idx = (reinterpret_cast<UIntPtr>(virtual_address) >> 30) & 0x1FF; + UInt64 l3_idx = (reinterpret_cast<UIntPtr>(virtual_address) >> 21) & 0x1FF; + + if (!l1_table[l1_idx]) return kErrorInvalidData; + + volatile UInt64* l2_table = reinterpret_cast<volatile UInt64*>(l1_table[l1_idx] & ~0xFFFUL); + + if (!l2_table[l2_idx]) return kErrorInvalidData; + + volatile UInt64* l3_table = reinterpret_cast<volatile UInt64*>(l2_table[l2_idx] & ~0xFFFUL); + + l3_table[l3_idx] = (reinterpret_cast<UInt64>(physical_address) & ~0xFFFUL) | flags; + + switch (level) { + case 2: { + l3_table[l3_idx] = (reinterpret_cast<UInt64>(physical_address) & ~0xFFFUL) | flags; + return kErrorSuccess; + } + case 1: { + l1_table[l1_idx] = (reinterpret_cast<UInt64>(physical_address) & ~0xFFFUL) | flags; + return kErrorSuccess; + } + case 0: { + l1_table[l1_idx] = (reinterpret_cast<UInt64>(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 new file mode 100644 index 00000000..467547b0 --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalSchedulerCore.cc @@ -0,0 +1,21 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <KernelKit/ProcessScheduler.h> + +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 new file mode 100644 index 00000000..b1728bac --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalSchedulerCorePrimitives.cc @@ -0,0 +1,30 @@ +/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <HALKit/ARM64/Processor.h>
+#include <KernelKit/ProcessScheduler.h>
+
+namespace Kernel {
+/***********************************************************************************/
+/// @brief Unimplemented function (crashes by default)
+/// @param process The process handle.
+/***********************************************************************************/
+
+EXTERN_C Void __ne_pure_call(USER_PROCESS* 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 new file mode 100644 index 00000000..2f524a1b --- /dev/null +++ b/src/kernel/HALKit/ARM64/HalTimer.cc @@ -0,0 +1,15 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: HalTimer.cc + Purpose: HAL timer + + Revision History: + + 07/07/24: Added file (amlel) + +======================================== */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/Timer.h>
\ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/Paging.h b/src/kernel/HALKit/ARM64/Paging.h new file mode 100644 index 00000000..766210b3 --- /dev/null +++ b/src/kernel/HALKit/ARM64/Paging.h @@ -0,0 +1,107 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +/** --------------------------------------------------- + + * THIS FILE CONTAINS CODE FOR ARMV8 PAGING. + +------------======================================== */ + +#ifdef __NE_ARM64__ + +#include <NeKit/Defines.h> + +#ifndef kPageMax +#define kPageMax (0x200) +#endif //! kPageMax + +#ifndef kPageAlign +#define kPageAlign (0x1000) +#endif //! kPageAlign + +#ifndef kPageSize +#define kPageSize (0x1000) +#endif // !kPageSize + +//! short format address range + +#define c16KBPage 0b000 +#define c8KBPage 0b001 +#define c4KBPage 0b010 +#define c2KBPage 0b011 +#define c1KBPage 0b100 +#define c512BPage 0b101 +#define c256BPage 0b110 +#define c128BPage 0b111 + +/// Long format address range + +#define cPageMAll \ + { 0b000, 0b000 } +#define cPageMToMax(M) \ + { M, 0b000 } +#define cPageMaxToM(M) \ + { 0b000, M } +#define cPageMToN(M, N) \ + { M, N } + +namespace Kernel::HAL { +struct PACKED PTE_4KB final { + UInt64 Valid : 1; + UInt64 Table : 1; + UInt64 AttrIndex : 3; + UInt64 NS : 1; + UInt64 AP : 2; + UInt64 SH : 2; + UInt64 AF : 1; + UInt64 NG : 1; + UInt64 Reserved1 : 1; + UInt64 Contiguous : 1; + UInt64 Dirty : 1; + UInt64 Reserved : 2; + UInt64 PhysicalAddress : 36; + UInt64 Reserved3 : 4; + UInt64 PXN : 1; + UInt64 XN : 1; + UInt64 Reserved4 : 9; +}; + +namespace Detail { + enum class ControlRegisterBits { + ProtectedModeEnable = 0, + MonitorCoProcessor = 1, + Emulation = 2, + TaskSwitched = 3, + ExtensionType = 4, + NumericError = 5, + WriteProtect = 16, + AlignementMask = 18, + NotWriteThrough = 29, + CacheDisable = 30, + PageEnable = 31, + }; + + inline UInt8 control_register_cast(ControlRegisterBits reg) { return static_cast<UInt8>(reg); } +} // namespace Detail + +struct PDE_4KB final { + PTE_4KB ALIGN(kPageAlign) fEntries[kPageMax]; +}; + +auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page, SizeT pad = 0) -> VoidPtr; +auto mm_free_bitmap(VoidPtr page_ptr) -> Bool; +} // namespace Kernel::HAL + +namespace Kernel { +typedef HAL::PTE_4KB PTE; +typedef HAL::PDE_4KB PDE; +} // namespace Kernel + +EXTERN_C void hal_flush_tlb(); + +#endif // __NE_ARM64__
\ No newline at end of file diff --git a/src/kernel/HALKit/ARM64/Processor.h b/src/kernel/HALKit/ARM64/Processor.h new file mode 100644 index 00000000..716d317b --- /dev/null +++ b/src/kernel/HALKit/ARM64/Processor.h @@ -0,0 +1,78 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#ifdef __NE_ARM64__ + +#include <FirmwareKit/Handover.h> +#include <NeKit/Array.h> +#include <NeKit/Defines.h> +#include <NeKit/Utils.h> + +#define kCPUBackendName "aarch64" + +namespace Kernel::HAL { +struct PACKED Register64 final { + UShort Limit; + UIntPtr Base; +}; + +/// @brief Memory Manager mapping flags. +enum { + kMMFlagsInvalid = 1 << 0, + kMMFlagsPresent = 1 << 1, + kMMFlagsWr = 1 << 2, + kMMFlagsUser = 1 << 3, + kMMFlagsNX = 1 << 4, + kMMFlagsCount = 4, +}; + +/// @brief Set a PTE from pd_base. +/// @param virt_addr 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 manip. +EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, + UInt32 level = 2); + +EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virtual_address); + +typedef UIntPtr Reg; +typedef Register64 Register; + +/// @note let's keep the same name as AMD64 HAL. +struct PACKED StackFrame { + Reg IP; + Reg SP; + Reg R8; + Reg R9; + Reg R10; + Reg R11; + Reg R12; + Reg R13; + Reg R14; + Reg R15; +}; + +typedef StackFrame* StackFramePtr; + +inline Void rt_halt() noexcept { + while (Yes) { + } +} + +inline Void hal_wfi(Void) { + asm volatile("wfi"); +} +} // namespace Kernel::HAL + +inline Kernel::VoidPtr kKernelBitMpStart = nullptr; +inline Kernel::UIntPtr kKernelBitMpSize = 0UL; + +#include <HALKit/ARM64/Paging.h> + +#endif // __NE_ARM64__
\ 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 new file mode 100644 index 00000000..0200ec5a --- /dev/null +++ b/src/kernel/HALKit/ARM64/Storage/SCSI+Generic.cc @@ -0,0 +1,13 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#include <modules/SCSI/SCSI.h> + +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 new file mode 100644 index 00000000..9971b2a8 --- /dev/null +++ b/src/kernel/HALKit/ARM64/Storage/UFS+Generic.cc @@ -0,0 +1,8 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +/// @file UFS.cc +/// @brief UFS Flash Memory support. |
