summaryrefslogtreecommitdiffhomepage
path: root/src/kernel/HALKit/AMD64
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/HALKit/AMD64')
-rw-r--r--src/kernel/HALKit/AMD64/CPUID.h89
-rw-r--r--src/kernel/HALKit/AMD64/CxxAbi.cc79
-rw-r--r--src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc113
-rw-r--r--src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc39
-rw-r--r--src/kernel/HALKit/AMD64/HalApplicationProcessor.cc221
-rw-r--r--src/kernel/HALKit/AMD64/HalApplicationProcessorStartup.s23
-rw-r--r--src/kernel/HALKit/AMD64/HalCommonAPI.asm137
-rw-r--r--src/kernel/HALKit/AMD64/HalControlRegisterAPI.s45
-rw-r--r--src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc168
-rw-r--r--src/kernel/HALKit/AMD64/HalCoreSystemCalls.cc9
-rw-r--r--src/kernel/HALKit/AMD64/HalDebugOutput.cc227
-rw-r--r--src/kernel/HALKit/AMD64/HalDebugProtocol.cc16
-rw-r--r--src/kernel/HALKit/AMD64/HalDescriptorLoader.cc71
-rw-r--r--src/kernel/HALKit/AMD64/HalHandoverStub.asm30
-rw-r--r--src/kernel/HALKit/AMD64/HalInterruptAPI.asm370
-rw-r--r--src/kernel/HALKit/AMD64/HalKernelMain.cc160
-rw-r--r--src/kernel/HALKit/AMD64/HalKernelPanic.cc58
-rw-r--r--src/kernel/HALKit/AMD64/HalPagingMgr.cc167
-rw-r--r--src/kernel/HALKit/AMD64/HalProcessor.cc89
-rw-r--r--src/kernel/HALKit/AMD64/HalRoutineWait.s11
-rw-r--r--src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc51
-rw-r--r--src/kernel/HALKit/AMD64/HalTimer.cc101
-rw-r--r--src/kernel/HALKit/AMD64/HalUtilsAPI.asm24
-rw-r--r--src/kernel/HALKit/AMD64/Hypervisor.h24
-rw-r--r--src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc129
-rw-r--r--src/kernel/HALKit/AMD64/PCI/DMA.cc72
-rw-r--r--src/kernel/HALKit/AMD64/PCI/Database.cc9
-rw-r--r--src/kernel/HALKit/AMD64/PCI/Device.cc142
-rw-r--r--src/kernel/HALKit/AMD64/PCI/Express.cc9
-rw-r--r--src/kernel/HALKit/AMD64/PCI/IO.cc7
-rw-r--r--src/kernel/HALKit/AMD64/PCI/Iterator.cc30
-rw-r--r--src/kernel/HALKit/AMD64/PCI/PCI.cc7
-rw-r--r--src/kernel/HALKit/AMD64/Paging.h91
-rw-r--r--src/kernel/HALKit/AMD64/Processor.h283
-rw-r--r--src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc600
-rw-r--r--src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc199
-rw-r--r--src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc9
-rw-r--r--src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc278
-rw-r--r--src/kernel/HALKit/AMD64/Storage/SCSI+Generic.cc13
39 files changed, 4200 insertions, 0 deletions
diff --git a/src/kernel/HALKit/AMD64/CPUID.h b/src/kernel/HALKit/AMD64/CPUID.h
new file mode 100644
index 00000000..0ab95c07
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/CPUID.h
@@ -0,0 +1,89 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+ File: CPUID.h
+ Purpose: CPUID flags.
+
+ Revision History:
+
+ 30/01/24: Added file (amlel)
+
+======================================== */
+
+#pragma once
+
+#include <NeKit/Defines.h>
+
+EXTERN_C {
+#include <cpuid.h>
+}
+
+namespace Kernel {
+
+enum {
+ kCPUFeatureSSE3 = 1 << 0,
+ kCPUFeaturePCLMUL = 1 << 1,
+ kCPUFeatureDTES64 = 1 << 2,
+ kCPUFeatureMONITOR = 1 << 3,
+ kCPUFeatureDS_CPL = 1 << 4,
+ kCPUFeatureVMX = 1 << 5,
+ kCPUFeatureSMX = 1 << 6,
+ kCPUFeatureEST = 1 << 7,
+ kCPUFeatureTM2 = 1 << 8,
+ kCPUFeatureSSSE3 = 1 << 9,
+ kCPUFeatureCID = 1 << 10,
+ kCPUFeatureSDBG = 1 << 11,
+ kCPUFeatureFMA = 1 << 12,
+ kCPUFeatureCX16 = 1 << 13,
+ kCPUFeatureXTPR = 1 << 14,
+ kCPUFeaturePDCM = 1 << 15,
+ kCPUFeaturePCID = 1 << 17,
+ kCPUFeatureDCA = 1 << 18,
+ kCPUFeatureSSE4_1 = 1 << 19,
+ kCPUFeatureSSE4_2 = 1 << 20,
+ kCPUFeatureX2APIC = 1 << 21,
+ kCPUFeatureMOVBE = 1 << 22,
+ kCPUFeaturePOP3C = 1 << 23,
+ kCPUFeatureECXTSC = 1 << 24,
+ kCPUFeatureAES = 1 << 25,
+ kCPUFeatureXSAVE = 1 << 26,
+ kCPUFeatureOSXSAVE = 1 << 27,
+ kCPUFeatureAVX = 1 << 28,
+ kCPUFeatureF16C = 1 << 29,
+ kCPUFeatureRDRAND = 1 << 30,
+ kCPUFeatureHYPERVISOR = 1 << 31,
+ kCPUFeatureFPU = 1 << 0,
+ kCPUFeatureVME = 1 << 1,
+ kCPUFeatureDE = 1 << 2,
+ kCPUFeaturePSE = 1 << 3,
+ kCPUFeatureEDXTSC = 1 << 4,
+ kCPUFeatureMSR = 1 << 5,
+ kCPUFeaturePAE = 1 << 6,
+ kCPUFeatureMCE = 1 << 7,
+ kCPUFeatureCX8 = 1 << 8,
+ kCPUFeatureAPIC = 1 << 9,
+ kCPUFeatureSEP = 1 << 11,
+ kCPUFeatureMTRR = 1 << 12,
+ kCPUFeaturePGE = 1 << 13,
+ kCPUFeatureMCA = 1 << 14,
+ kCPUFeatureCMOV = 1 << 15,
+ kCPUFeaturePAT = 1 << 16,
+ kCPUFeaturePSE36 = 1 << 17,
+ kCPUFeaturePSN = 1 << 18,
+ kCPUFeatureCLFLUSH = 1 << 19,
+ kCPUFeatureDS = 1 << 21,
+ kCPUFeatureACPI = 1 << 22,
+ kCPUFeatureMMX = 1 << 23,
+ kCPUFeatureFXSR = 1 << 24,
+ kCPUFeatureSSE = 1 << 25,
+ kCPUFeatureSSE2 = 1 << 26,
+ kCPUFeatureSS = 1 << 27,
+ kCPUFeatureHTT = 1 << 28,
+ kCPUFeatureTM = 1 << 29,
+ kCPUFeatureIA64 = 1 << 30,
+ kCPUFeaturePBE = 1 << 31
+};
+
+typedef Int64 CPUID;
+} // namespace Kernel
diff --git a/src/kernel/HALKit/AMD64/CxxAbi.cc b/src/kernel/HALKit/AMD64/CxxAbi.cc
new file mode 100644
index 00000000..9049457b
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/CxxAbi.cc
@@ -0,0 +1,79 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <KernelKit/DebugOutput.h>
+#include <KernelKit/KPC.h>
+#include <KernelKit/UserProcessScheduler.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 Kernel::Void __cxa_pure_virtual(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 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
new file mode 100644
index 00000000..83545df8
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc
@@ -0,0 +1,113 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <ArchKit/ArchKit.h>
+#include <HALKit/AMD64/Processor.h>
+#include <KernelKit/HeapMgr.h>
+#include <NeKit/KString.h>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+
+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
new file mode 100644
index 00000000..36a027a2
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalAPICDmaWrapper.cc
@@ -0,0 +1,39 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <HALKit/AMD64/Processor.h>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+
+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) noexcept {
+ 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) noexcept {
+ 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
new file mode 100644
index 00000000..5a530457
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalApplicationProcessor.cc
@@ -0,0 +1,221 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+/// Different than the MADT, might be confusing to some.
+#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 <ArchKit/ArchKit.h>
+#include <HALKit/AMD64/Processor.h>
+#include <KernelKit/BinaryMutex.h>
+#include <KernelKit/HardwareThreadScheduler.h>
+#include <KernelKit/ProcessScheduler.h>
+#include <KernelKit/Timer.h>
+#include <NeKit/KernelPanic.h>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <modules/CoreGfx/TextGfx.h>
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+/// @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<UInt32>(target, APIC_ICR_HIGH, apic_id << 24);
+ Kernel::ke_dma_write<UInt32>(target, APIC_ICR_LOW, 0x00000600 | 0x00004000 | 0x00000000 | vector);
+
+ while (Kernel::ke_dma_read<UInt32>(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(kHWThread[thrdid].mFramePtr);
+ return YES;
+ }
+
+ if (thrdid > kSMPCount) return NO;
+
+ HardwareThreadScheduler::The()[thrdid].Leak()->Busy(NO);
+ kHWThread[thrdid].mFramePtr = stack_frame;
+
+ return YES;
+}
+
+/***********************************************************************************/
+/// @brief Is the current config SMP aware?
+/// @return True if YES, False if not.
+/***********************************************************************************/
+
+Bool mp_is_smp(Void) noexcept {
+ return kSMPAware;
+}
+
+/***********************************************************************************/
+/// @brief Fetch and enable SMP scheduler.
+/// @param vendor_ptr SMP containing structure.
+/***********************************************************************************/
+
+Void mp_init_cores(VoidPtr vendor_ptr) noexcept {
+ 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<HAL_APIC_MADT*>(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<volatile UInt8*>(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;
+ }
+
+ kSMPAware = kSMPCount > 1;
+ }
+}
+} // namespace Kernel::HAL
+
+///////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/kernel/HALKit/AMD64/HalApplicationProcessorStartup.s b/src/kernel/HALKit/AMD64/HalApplicationProcessorStartup.s
new file mode 100644
index 00000000..7b383404
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalApplicationProcessorStartup.s
@@ -0,0 +1,23 @@
+ /*
+ * ========================================================
+ *
+ * NeKernel
+ * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+ *
+ * ========================================================
+ */
+
+.text
+
+.global hal_ap_blob_start
+.global hal_ap_blob_length
+
+hal_ap_blob_start:
+ cli
+ hlt
+ jmp hal_ap_blob_start
+
+.data
+
+hal_ap_blob_length:
+ .long 4
diff --git a/src/kernel/HALKit/AMD64/HalCommonAPI.asm b/src/kernel/HALKit/AMD64/HalCommonAPI.asm
new file mode 100644
index 00000000..9f3652bc
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalCommonAPI.asm
@@ -0,0 +1,137 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+;; *
+;; * ========================================================
+;; */
+
+section .text
+
+extern rt_wait_400ns
+
+global rt_out8
+global rt_out16
+global rt_out32
+
+global rt_in8
+global rt_in16
+global rt_in32
+
+rt_out8:
+ mov al, dl
+ mov dx, cx
+ out dx, al
+ ret
+
+rt_out16:
+ mov ax, dx
+ mov dx, cx
+ out dx, ax
+ ret
+
+rt_out32:
+ mov eax, edx
+ mov edx, ecx
+ out dx, eax
+ ret
+
+rt_in8:
+ mov dx, cx
+ in al, dx
+ ret
+
+rt_in16:
+ mov edx, ecx
+ in ax, dx
+ ret
+
+rt_in32:
+ mov rdx, rcx
+ in eax, dx
+ ret
+
+extern hal_system_call_enter
+global mp_system_call_handler
+
+mp_system_call_handler:
+ push rbp
+ mov rbp, rsp
+
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ jmp hal_system_call_enter
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+
+ pop rbp
+
+ o64 iret
+
+
+section .text
+
+global sched_jump_to_task
+
+sched_jump_to_task:
+ push rbp
+ mov rbp, rsp
+
+ mov ax, 0x30
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov ax, 0x18
+ ltr ax
+
+ push 0x30
+ mov rdx, [rcx + 0x08]
+ push rdx
+ o64 pushf
+ push 0x28
+ mov rdx, [rcx + 0x00]
+ push rdx
+
+ call sched_recover_registers
+
+ o64 iret
+
+global sched_idle_task
+
+sched_idle_task:
+ jmp $
+ ret
+
+sched_recover_registers:
+ push rbp
+ mov rbp, rsp
+
+ mov r8, [rcx + 0x10]
+ mov r9, [rcx + 0x18]
+ mov r10, [rcx + 0x20]
+ mov r11, [rcx + 0x28]
+ mov r12, [rcx + 0x30]
+ mov r13, [rcx + 0x38]
+ mov r14, [rcx + 0x40]
+ mov r15, [rcx + 0x48]
+
+ pop rbp
+
+ ret \ No newline at end of file
diff --git a/src/kernel/HALKit/AMD64/HalControlRegisterAPI.s b/src/kernel/HALKit/AMD64/HalControlRegisterAPI.s
new file mode 100644
index 00000000..90fdeb81
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalControlRegisterAPI.s
@@ -0,0 +1,45 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+.globl hal_write_cr3
+.globl hal_write_cr0
+.globl hal_read_cr2
+.globl hal_read_cr3
+.globl hal_read_cr0
+.globl hal_flush_tlb
+.globl hal_invl_tlb
+
+.text
+
+hal_invl_tlb:
+ invlpg (%rcx)
+ retq
+
+hal_flush_tlb:
+ call hal_read_cr3
+ mov %rax, %rcx
+ call hal_write_cr3
+ retq
+
+hal_read_cr3:
+ movq %cr3, %rax
+ retq
+
+hal_read_cr0:
+ movq %cr0, %rax
+ retq
+
+hal_read_cr2:
+ movq %cr2, %rax
+ retq
+
+hal_write_cr3:
+ movq %rcx, %cr3
+ retq
+
+hal_write_cr0:
+ movq %rcx, %cr0
+ retq
diff --git a/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc b/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc
new file mode 100644
index 00000000..f19e49b5
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc
@@ -0,0 +1,168 @@
+/* ========================================
+
+ 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 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();
+ process.Leak().Crash();
+
+ hal_idt_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 idt_handle_pf(Kernel::UIntPtr rsp) {
+ auto& process = Kernel::UserProcessScheduler::The().TheCurrentProcess();
+ process.Leak().Crash();
+
+ hal_idt_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 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();
+ process.Leak().Crash();
+
+ hal_idt_send_eoi(8);
+
+ process.Leak().Signal.SignalArg = rsp;
+ process.Leak().Signal.SignalID = sig_generate_unique<SIGKILL>();
+ ;
+ process.Leak().Signal.Status = process.Leak().Status;
+}
+
+/// @brief Handle any generic fault.
+/// @param rsp
+EXTERN_C void idt_handle_generic(Kernel::UIntPtr rsp) {
+ auto& process = Kernel::UserProcessScheduler::The().TheCurrentProcess();
+ process.Leak().Crash();
+
+ hal_idt_send_eoi(30);
+
+ Kernel::kout << "Kernel: Generic Process Fault.\r";
+
+ process.Leak().Signal.SignalArg = rsp;
+ process.Leak().Signal.SignalID = sig_generate_unique<SIGSEG>();
+ ;
+ process.Leak().Signal.Status = process.Leak().Status;
+
+ Kernel::kout << "Kernel: SIGKILL status.\r";
+}
+
+EXTERN_C Kernel::Void idt_handle_breakpoint(Kernel::UIntPtr rip) {
+ auto& process = Kernel::UserProcessScheduler::The().TheCurrentProcess();
+
+ hal_idt_send_eoi(3);
+
+ process.Leak().Signal.SignalArg = rip;
+ process.Leak().Signal.SignalID = sig_generate_unique<SIGTRAP>();
+
+ process.Leak().Signal.Status = process.Leak().Status;
+
+ process.Leak().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();
+ process.Leak().Crash();
+
+ hal_idt_send_eoi(6);
+
+ process.Leak().Signal.SignalArg = rsp;
+ process.Leak().Signal.SignalID = sig_generate_unique<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_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.cc b/src/kernel/HALKit/AMD64/HalCoreSystemCalls.cc
new file mode 100644
index 00000000..f50e4abd
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalCoreSystemCalls.cc
@@ -0,0 +1,9 @@
+/* ========================================
+
+ Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+ ======================================== */
+
+#include <ArchKit/ArchKit.h>
+
+using namespace Kernel;
diff --git a/src/kernel/HALKit/AMD64/HalDebugOutput.cc b/src/kernel/HALKit/AMD64/HalDebugOutput.cc
new file mode 100644
index 00000000..8e5f4cbd
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalDebugOutput.cc
@@ -0,0 +1,227 @@
+/* ========================================
+
+ 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>
+#include <modules/CoreGfx/CoreGfx.h>
+#include <modules/CoreGfx/TextGfx.h>
+
+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 <UInt16 PORT>
+ bool hal_serial_init() noexcept {
+ 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(DeviceInterface<const Utf8Char*>* obj, const Utf8Char* bytes) {
+ NE_UNUSED(bytes);
+ NE_UNUSED(obj);
+
+#ifdef __DEBUG__
+ Detail::hal_serial_init<Detail::kPort>();
+
+ 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(DeviceInterface<const Char*>* obj, const Char* bytes) {
+ NE_UNUSED(bytes);
+ NE_UNUSED(obj);
+
+#ifdef __DEBUG__
+ Detail::hal_serial_init<Detail::kPort>();
+
+ 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(DeviceInterface<const Char*>*, const Char* bytes) {
+ NE_UNUSED(bytes);
+
+#ifdef __DEBUG__
+ Detail::hal_serial_init<Detail::kPort>();
+
+ 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() noexcept {
+ TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read);
+ return out;
+}
+
+Utf8TerminalDevice::~Utf8TerminalDevice() = default;
+
+Utf8TerminalDevice Utf8TerminalDevice::The() noexcept {
+ Utf8TerminalDevice out(Kernel::ke_utf_io_write,
+ [](DeviceInterface<const Utf8Char*>*, const Utf8Char*) -> Void {});
+ return out;
+}
+
+} // namespace Kernel
diff --git a/src/kernel/HALKit/AMD64/HalDebugProtocol.cc b/src/kernel/HALKit/AMD64/HalDebugProtocol.cc
new file mode 100644
index 00000000..1adfff3e
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalDebugProtocol.cc
@@ -0,0 +1,16 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+//! @file DebuggerPort.cc
+//! @brief UART debug via packets.
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/DebugOutput.h>
+#include <NetworkKit/NetworkDevice.h>
+
+// 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
new file mode 100644
index 00000000..65bf0b1e
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalDescriptorLoader.cc
@@ -0,0 +1,71 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <ArchKit/ArchKit.h>
+#include <FSKit/NeFS.h>
+#include <HALKit/AMD64/Processor.h>
+
+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<Register64>& 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<Register64>& idt) {
+ if (!idt) return;
+
+ IDTLoader::Load(idt.Leak());
+}
+} // namespace Kernel::HAL
diff --git a/src/kernel/HALKit/AMD64/HalHandoverStub.asm b/src/kernel/HALKit/AMD64/HalHandoverStub.asm
new file mode 100644
index 00000000..c9cabd1c
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalHandoverStub.asm
@@ -0,0 +1,30 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+;; *
+;; * ========================================================
+;; */
+
+[bits 64]
+
+%define kTypeKernel 100
+%define kArchAmd64 122
+%define kHandoverMagic 0xBADCC
+
+global _HandoverMagic
+global _HandoverType
+global _HandoverPad
+global _HandoverArch
+
+section .ldr
+
+_HandoverMagic:
+ dq kHandoverMagic
+_HandoverType:
+ dw kTypeKernel
+_HandoverPad:
+ dw 0
+_HandoverArch:
+ dw kArchAmd64
diff --git a/src/kernel/HALKit/AMD64/HalInterruptAPI.asm b/src/kernel/HALKit/AMD64/HalInterruptAPI.asm
new file mode 100644
index 00000000..c761684e
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalInterruptAPI.asm
@@ -0,0 +1,370 @@
+;; /*
+;; * ---------------------------------------------------
+;; *
+;; * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+;; *
+;; * File: HalInterruptAPI.asm
+;; * Purpose: Interrupt API, redirect raw interrupts into their handlers.
+;; *
+;; * ---------------------------------------------------
+;; */
+
+[bits 64]
+
+%define kInterruptId 50
+
+%macro IntExp 1
+global __NE_INT_%1
+__NE_INT_%1:
+ cli
+
+ std
+
+ o64 iret
+%endmacro
+
+%macro IntNormal 1
+global __NE_INT_%1
+__NE_INT_%1:
+ cli
+
+ std
+
+ add rsp, 8
+
+ o64 iret
+%endmacro
+
+; This file handles the core interrupt table
+; Last edited 31/01/24
+
+global ke_handle_irq
+global kInterruptVectorTable
+
+extern idt_handle_gpf
+extern idt_handle_pf
+extern ke_io_write
+extern idt_handle_ud
+extern idt_handle_generic
+extern idt_handle_breakpoint
+extern idt_handle_math
+
+section .text
+
+__NE_INT_0:
+ cli
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_1:
+ cli
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_2:
+ cli
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+;; @brief Triggers a breakpoint and freeze the process. RIP is also fetched.
+__NE_INT_3:
+ cli
+ push rcx
+ call idt_handle_breakpoint
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_4:
+ cli
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_5:
+ cli
+ std
+
+ o64 iret
+
+;; Invalid opcode interrupt
+__NE_INT_6:
+ cli
+ push rcx
+ call idt_handle_ud
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_7:
+ cli
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+;; Invalid opcode interrupt
+__NE_INT_8:
+ cli
+
+ push rcx
+ call idt_handle_math
+ pop rcx
+
+ std
+
+ o64 iret
+
+IntNormal 9
+IntExp 10
+IntExp 11
+
+IntExp 12
+
+__NE_INT_13:
+ cli
+
+ push rcx
+ call idt_handle_gpf
+ pop rcx
+
+ std
+
+ add rsp, 8
+
+ o64 iret
+
+__NE_INT_14:
+ cli
+ push rcx
+ call idt_handle_pf
+ pop rcx
+
+ std
+
+ o64 iret
+
+IntNormal 15
+IntNormal 16
+IntExp 17
+IntNormal 18
+IntNormal 19
+IntNormal 20
+IntNormal 21
+
+IntNormal 22
+
+IntNormal 23
+IntNormal 24
+IntNormal 25
+IntNormal 26
+IntNormal 27
+IntNormal 28
+IntNormal 29
+IntExp 30
+IntNormal 31
+
+[extern idt_handle_scheduler]
+[extern kApicBaseAddress]
+
+__NE_INT_32:
+ cli
+
+ push rax
+ mov rcx, rsp
+ call idt_handle_scheduler
+ pop rax
+
+ std
+
+ o64 iret
+
+IntNormal 33
+
+IntNormal 34
+IntNormal 35
+IntNormal 36
+IntNormal 37
+IntNormal 38
+IntNormal 39
+
+[extern rtl_rtl8139_interrupt_handler]
+
+__NE_INT_40:
+ cli
+
+ push rax
+ mov rcx, rsp
+ call rtl_rtl8139_interrupt_handler
+ pop rax
+
+ std
+
+ o64 iret
+
+IntNormal 41
+
+IntNormal 42
+IntNormal 43
+IntNormal 44
+IntNormal 45
+IntNormal 46
+IntNormal 47
+IntNormal 48
+IntNormal 49
+
+[extern hal_system_call_enter]
+[extern hal_kernel_call_enter]
+
+__NE_INT_50:
+ cli
+
+ push rax
+ mov rax, hal_system_call_enter
+
+ mov rcx, r8
+ mov rdx, r9
+ mov r8, r10
+ mov r9, r11
+
+ call rax
+ pop rax
+
+ std
+
+ o64 iret
+
+__NE_INT_51:
+ cli
+
+ push rax
+ mov rax, hal_kernel_call_enter
+
+ mov rcx, r8
+ mov rdx, r9
+ mov r8, r10
+ mov r9, r11
+
+ call rax
+ pop rax
+
+ std
+
+ o64 iret
+
+IntNormal 52
+
+IntNormal 53
+IntNormal 54
+IntNormal 55
+IntNormal 56
+IntNormal 57
+IntNormal 58
+IntNormal 59
+IntNormal 60
+
+%assign i 61
+%rep 195
+ IntNormal i
+%assign i i+1
+%endrep
+
+section .text
+
+[global hal_load_gdt]
+
+hal_load_gdt:
+ cli
+
+ lgdt [rcx]
+
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov rax, 0x08
+ push rax
+ push hal_reload_segments
+
+ o64 retf
+
+extern hal_real_init
+
+hal_reload_segments:
+ std
+ jmp hal_real_init
+ ret
+
+global hal_load_idt
+
+hal_load_idt:
+ lidt [rcx]
+
+ ; Master PIC initialization
+ mov al, 0x11 ; Start initialization in cascade mode
+ out 0x20, al ; Send initialization command to Master PIC
+ out 0xA0, al ; Send initialization command to Slave PIC
+
+ ; Remap the PIC to use vectors 32-39 for Master and 40-47 for Slave
+ mov al, 0x20 ; Set Master PIC offset to 32
+ out 0x21, al ; Send offset to Master PIC
+
+ mov al, 0x28 ; Set Slave PIC offset to 40
+ out 0xA1, al ; Send offset to Slave PIC
+
+ ; Configure Master PIC to inform Slave PIC at IRQ2
+ mov al, 0x04 ; Tell Master PIC there is a Slave PIC at IRQ2
+ out 0x21, al
+
+ ; Configure Slave PIC identity
+ mov al, 0x02 ; Tell Slave PIC its cascade identity
+ out 0xA1, al
+
+ ; Set both PICs to 8086 mode
+ mov al, 0x01 ; 8086 mode
+ out 0x21, al
+ out 0xA1, al
+
+ ret
+
+section .data
+
+kInterruptVectorTable:
+ %assign i 0
+ %rep 256
+ dq __NE_INT_%+i
+ %assign i i+1
+ %endrep
+
+kApicBaseAddress:
+ dq 0 \ No newline at end of file
diff --git a/src/kernel/HALKit/AMD64/HalKernelMain.cc b/src/kernel/HALKit/AMD64/HalKernelMain.cc
new file mode 100644
index 00000000..e23c5bc1
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalKernelMain.cc
@@ -0,0 +1,160 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <ArchKit/ArchKit.h>
+#include <CFKit/Property.h>
+#include <FirmwareKit/EFI/API.h>
+#include <FirmwareKit/EFI/EFI.h>
+#include <KernelKit/CodeMgr.h>
+#include <KernelKit/HardwareThreadScheduler.h>
+#include <KernelKit/ProcessScheduler.h>
+#include <KernelKit/Timer.h>
+#include <NetworkKit/IPC.h>
+#include <StorageKit/AHCI.h>
+#include <misc/BenchKit/HWChronometer.h>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <modules/CoreGfx/TextGfx.h>
+
+#ifndef __NE_MODULAR_KERNEL_COMPONENTS__
+EXTERN_C Kernel::VoidPtr kInterruptVectorTable[];
+
+/// @brief Kernel init function.
+/// @param handover_hdr Handover boot header.
+EXTERN_C 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<VoidPtr>(reinterpret_cast<UIntPtr>(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<UIntPtr>(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) {
+#ifdef __FSKIT_INCLUDES_OPENHEFS__
+ OpenHeFS::fs_init_openhefs();
+#endif
+
+#ifdef __FSKIT_INCLUDES_NEFS__
+ NeFS::fs_init_nefs();
+#endif
+
+ UserProcessScheduler::The().SwitchTeam(kHighUserTeam);
+
+ rtl_create_user_process([]() -> void { while (YES); }, "NeKernel");
+
+ HAL::mp_init_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr);
+
+ HAL::Register64 idt_reg;
+ idt_reg.Base = reinterpret_cast<UIntPtr>(kInterruptVectorTable);
+
+ HAL::IDTLoader idt_loader;
+ idt_loader.Load(idt_reg);
+
+ while (YES)
+ ;
+}
+#endif // ifndef __NE_MODULAR_KERNEL_COMPONENTS__
diff --git a/src/kernel/HALKit/AMD64/HalKernelPanic.cc b/src/kernel/HALKit/AMD64/HalKernelPanic.cc
new file mode 100644
index 00000000..12538667
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalKernelPanic.cc
@@ -0,0 +1,58 @@
+/* ========================================
+
+ 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);
+ (Void)(kout << "Kernel_Panic_CR2: " << hex_number((UIntPtr) hal_read_cr2()) << 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 << "*** 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
new file mode 100644
index 00000000..4043da96
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalPagingMgr.cc
@@ -0,0 +1,167 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+ File: HalPagingMgr.cc
+ Purpose: Platform Paging Manager.
+
+======================================== */
+
+#include <HALKit/AMD64/Paging.h>
+#include <HALKit/AMD64/Processor.h>
+
+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<UInt64*>(cr3);
+ UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9Bits];
+
+ if (!(pml4e & 1)) return 0;
+
+ // Level 3
+ auto pdpt = reinterpret_cast<UInt64*>(pml4e & ~kPageOffsetMask);
+ UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9Bits];
+
+ if (!(pdpte & 1)) return 0;
+
+ // Level 2
+ auto pd = reinterpret_cast<UInt64*>(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<UInt64*>(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<UInt64*>(cr3);
+ UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9];
+
+ if (!(pml4e & 1)) return kErrorInvalidData;
+
+ UInt64* pdpt = reinterpret_cast<UInt64*>(pml4e & ~kPageMask);
+ UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9];
+
+ if (!(pdpte & 1)) return kErrorInvalidData;
+
+ UInt64* pd = reinterpret_cast<UInt64*>(pdpte & ~kPageMask);
+ UInt64 pde = pd[(kVMAddr >> 21) & kMask9];
+
+ if (!(pde & 1)) return kErrorInvalidData;
+
+ UInt64* pt = reinterpret_cast<UInt64*>(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
new file mode 100644
index 00000000..d202a758
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalProcessor.cc
@@ -0,0 +1,89 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+ File: HalCPU.cc
+ Purpose: Platform processor routines.
+
+======================================== */
+
+#include <HALKit/AMD64/Paging.h>
+#include <HALKit/AMD64/Processor.h>
+
+/**
+ * @file HalCPU.cc
+ * @brief Common CPU API.
+ */
+
+namespace Kernel::HAL {
+inline Bool hal_has_msr() noexcept {
+ 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) noexcept {
+ if (!lo || !hi) return;
+ asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
+}
+
+Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) noexcept {
+ 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/HalRoutineWait.s b/src/kernel/HALKit/AMD64/HalRoutineWait.s
new file mode 100644
index 00000000..89051ba4
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalRoutineWait.s
@@ -0,0 +1,11 @@
+.globl rt_wait_400ns
+
+.section .text
+rt_wait_400ns:
+ jmp .loop
+ pause
+ .loop:
+ jmp .loop2
+ pause
+ .loop2:
+ ret
diff --git a/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc b/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc
new file mode 100644
index 00000000..44ec2a37
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalSchedulerCorePrimitives.cc
@@ -0,0 +1,51 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <HALKit/AMD64/Processor.h>
+#include <KernelKit/ProcessScheduler.h>
+
+namespace Kernel {
+/***********************************************************************************/
+/// @brief Unimplemented function (crashes by default)
+/// @param
+/***********************************************************************************/
+
+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;
+}
+
+/// @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
new file mode 100644
index 00000000..f6488b05
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalTimer.cc
@@ -0,0 +1,101 @@
+/* ========================================
+
+ 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>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+
+/// ================================================================================
+/// @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() noexcept {
+ 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/HalUtilsAPI.asm b/src/kernel/HALKit/AMD64/HalUtilsAPI.asm
new file mode 100644
index 00000000..2a0a5eff
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/HalUtilsAPI.asm
@@ -0,0 +1,24 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+;; *
+;; * ========================================================
+;; */
+
+[bits 64]
+
+[global rt_install_tib]
+
+section .text
+
+;; changed: rs, fs
+;; expected: rcx, rdx
+
+rt_install_tib:
+ mov rcx, gs ;; TIB -> Thread Information Block
+ mov rdx, fs ;; PIB -> Process Information Block
+ ret
+
+;; //////////////////////////////////////////////////// ;;
diff --git a/src/kernel/HALKit/AMD64/Hypervisor.h b/src/kernel/HALKit/AMD64/Hypervisor.h
new file mode 100644
index 00000000..4cacb003
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Hypervisor.h
@@ -0,0 +1,24 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#include <NeKit/Defines.h>
+
+namespace Kernel {
+MAKE_STRING_ENUM(HYPERVISOR)
+ENUM_STRING(Qemu, "TCGTCGTCGTCG");
+ENUM_STRING(KVM, " KVMKVMKVM ");
+ENUM_STRING(VMWare, "VMwareVMware");
+ENUM_STRING(VirtualBox, "VBoxVBoxVBox");
+ENUM_STRING(Xen, "XenVMMXenVMM");
+ENUM_STRING(Microsoft, "Microsoft Hv");
+ENUM_STRING(Parallels, " prl hyperv ");
+ENUM_STRING(ParallelsAlt, " lrpepyh vr ");
+ENUM_STRING(Bhyve, "bhyve bhyve ");
+ENUM_STRING(Qnx, " QNXQVMBSQG ");
+END_STRING_ENUM()
+} // namespace Kernel
diff --git a/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc b/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc
new file mode 100644
index 00000000..f9865139
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Network/Generic+Basic+RTL8139.cc
@@ -0,0 +1,129 @@
+/* ========================================
+
+Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <DmaKit/DmaPool.h>
+#include <HALKit/AMD64/Processor.h>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+
+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) noexcept {
+ if (kTXRXEnabled) return NO;
+
+ kRTLIOBase = io_base;
+
+ MUST_PASS(io_base != 0xFFFF);
+
+ kRXBuffer = reinterpret_cast<UInt8*>(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
new file mode 100644
index 00000000..809494b6
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/DMA.cc
@@ -0,0 +1,72 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/PCI/DMA.h>
+
+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<UIntPtr>(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<UIntPtr>(this->fAddress) + offset) << kendl);
+
+ ke_dma_write<UInt32>(reinterpret_cast<UIntPtr>(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<UIntPtr>(this->fAddress) + offset) << kendl);
+
+ return (UIntPtr) ke_dma_read<UInt32>(reinterpret_cast<UIntPtr>(this->fAddress), offset);
+}
+
+UIntPtr DMAWrapper::operator[](UIntPtr& offset) {
+ return this->Read(offset);
+}
+
+OwnPtr<IOBuf<Char*>> DMAFactory::Construct(OwnPtr<DMAWrapper>& dma) {
+ if (!dma) return {};
+
+ OwnPtr<IOBuf<Char*>> dmaOwnPtr =
+ mm_make_own_ptr<IOBuf<Char*>, char*>(reinterpret_cast<char*>(dma->fAddress));
+
+ if (!dmaOwnPtr) return {};
+
+ kout << "Returning the new OwnPtr<IOBuf<Char*>>!\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
new file mode 100644
index 00000000..ba3e946c
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/Database.cc
@@ -0,0 +1,9 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <KernelKit/PCI/Database.h>
+
+namespace Kernel {}
diff --git a/src/kernel/HALKit/AMD64/PCI/Device.cc b/src/kernel/HALKit/AMD64/PCI/Device.cc
new file mode 100644
index 00000000..65af2f25
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/Device.cc
@@ -0,0 +1,142 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/PCI/Device.h>
+
+#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<UIntPtr>(bar & ~0x03);
+
+ if (bar & PCI_BAR_64) {
+ UInt32 high = NE_PCIReadRaw((bar_in + 4) & ~0x03, fBus, fDevice, fFunction);
+ return (static_cast<UIntPtr>(high) << 32) | (bar & ~0x0F);
+ }
+
+ return static_cast<UIntPtr>(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
new file mode 100644
index 00000000..2b6ba8d3
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/Express.cc
@@ -0,0 +1,9 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <KernelKit/PCI/Express.h>
+
+namespace Kernel {}
diff --git a/src/kernel/HALKit/AMD64/PCI/IO.cc b/src/kernel/HALKit/AMD64/PCI/IO.cc
new file mode 100644
index 00000000..233c8ef2
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/IO.cc
@@ -0,0 +1,7 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <KernelKit/PCI/IO.h>
diff --git a/src/kernel/HALKit/AMD64/PCI/Iterator.cc b/src/kernel/HALKit/AMD64/PCI/Iterator.cc
new file mode 100644
index 00000000..103ddb2c
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/Iterator.cc
@@ -0,0 +1,30 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <KernelKit/PCI/Iterator.h>
+
+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<PCI::Device> 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
new file mode 100644
index 00000000..a8c48fb9
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/PCI/PCI.cc
@@ -0,0 +1,7 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <KernelKit/PCI/PCI.h>
diff --git a/src/kernel/HALKit/AMD64/Paging.h b/src/kernel/HALKit/AMD64/Paging.h
new file mode 100644
index 00000000..a938700e
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Paging.h
@@ -0,0 +1,91 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#ifdef __NE_AMD64__
+
+/** ---------------------------------------------------
+
+ * THIS FILE CONTAINS CODE FOR X86_64 PAGING.
+
+------------======================================== */
+
+#include <NeKit/Defines.h>
+
+#ifndef kPageMax
+#define kPageMax (0x200)
+#endif //! kPageMax
+
+#ifndef kPageAlign
+#define kPageAlign (0x08)
+#endif //! kPageAlign
+
+#ifndef kPageSize
+#define kPageSize (0x1000)
+#endif // !kPageSize
+
+#ifndef kAlign
+#define kAlign __BIGGEST_ALIGNMENT__
+#endif // !kAlign
+
+EXTERN_C void hal_flush_tlb();
+EXTERN_C void hal_invl_tlb(Kernel::VoidPtr addr);
+EXTERN_C void hal_write_cr3(Kernel::VoidPtr cr3);
+EXTERN_C void hal_write_cr0(Kernel::VoidPtr bit);
+
+EXTERN_C Kernel::VoidPtr hal_read_cr0(); // @brief CPU control register.
+EXTERN_C Kernel::VoidPtr hal_read_cr2(); // @brief Fault address.
+EXTERN_C Kernel::VoidPtr hal_read_cr3(); // @brief Page directory inside cr3 register.
+
+namespace Kernel::HAL {
+namespace Detail {
+ enum class ControlRegisterBits {
+ kProtectedModeEnable = 0,
+ kMonitorCoProcessor = 1,
+ kEmulation = 2,
+ kTaskSwitched = 3,
+ kExtensionType = 4,
+ kNumericError = 5,
+ kWriteProtect = 16,
+ kAlignementMask = 18,
+ kNotWriteThrough = 29,
+ kCacheDisable = 30,
+ kPageEnable = 31,
+ };
+
+ inline UInt8 control_register_cast(ControlRegisterBits reg) { return static_cast<UInt8>(reg); }
+} // namespace Detail
+
+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 {
+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
+};
+
+struct PDE {
+ ATTRIBUTE(aligned(kib_cast(4))) PTE fPTE[512];
+};
+} // namespace Kernel
+
+#endif // __NE_AMD64__ \ No newline at end of file
diff --git a/src/kernel/HALKit/AMD64/Processor.h b/src/kernel/HALKit/AMD64/Processor.h
new file mode 100644
index 00000000..db1ed573
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Processor.h
@@ -0,0 +1,283 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+ File: Prcoessor.h
+ Purpose: AMD64 processor abstraction.
+
+ Revision History:
+
+ 30/01/24: Added file (amlel)
+
+======================================== */
+
+#pragma once
+
+#ifdef __NE_AMD64__
+
+#include <FirmwareKit/Handover.h>
+#include <HALKit/AMD64/Paging.h>
+#include <NeKit/Array.h>
+#include <NeKit/Defines.h>
+#include <NeKit/Utils.h>
+
+#include <HALKit/AMD64/CPUID.h>
+
+#define kPITControlPort (0x43)
+#define kPITChannel0Port (0x40)
+#define kPITFrequency (1193180)
+
+#define kPICCommand (0x20)
+#define kPICData (0x21)
+#define kPIC2Command (0xA0)
+#define kPIC2Data (0xA1)
+
+#define kIOAPICRegVal (4)
+#define kIOAPICRegReg (0)
+
+#define rtl_nop_op() asm volatile("nop")
+
+/// @brief Maximum entries of the interrupt descriptor table.
+#define kKernelIdtSize (0x100)
+
+/// @brief interrupt for system call.
+#define kKernelInterruptId (0x32)
+
+#define IsActiveLow(FLG) (FLG & 2)
+#define IsLevelTriggered(FLG) (FLG & 8)
+
+#define kInterruptGate (0x8E)
+#define kUserInterruptGate (0xEE)
+#define kTrapGate (0xEF)
+#define kTaskGate (0b10001100)
+#define kIDTSelector (0x08)
+
+namespace Kernel {
+namespace Detail::AMD64 {
+ struct PACKED InterruptDescriptorAMD64 final {
+ UInt16 OffsetLow; // offset bits 0..15
+ UInt16 Selector; // a code segment selector in GDT or LDT
+ UInt8 Ist;
+ UInt8 TypeAttributes;
+ UInt16 OffsetMid;
+ UInt32 OffsetHigh;
+ UInt32 Zero; // reserved
+ };
+} // namespace Detail::AMD64
+} // namespace Kernel
+
+namespace Kernel::HAL {
+/// @brief Memory Manager mapping flags.
+enum {
+ kMMFlagsInvalid = 1 << 0,
+ kMMFlagsPresent = 1 << 1,
+ kMMFlagsWr = 1 << 2,
+ kMMFlagsUser = 1 << 3,
+ kMMFlagsNX = 1 << 4,
+ kMMFlagsPCD = 1 << 5,
+ kMMFlagsPwt = 1 << 6,
+ kMMFlagsCount = 6,
+};
+
+struct PACKED Register64 final {
+ UShort Limit;
+ UIntPtr Base;
+};
+
+using RawRegister = UInt64;
+using Reg = RawRegister;
+using InterruptId = UInt16; /* For each element in the IVT */
+
+/// @brief Stack frame (as retrieved from assembly.)
+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;
+
+class InterruptDescriptor final {
+ public:
+ UShort Offset;
+ UShort Selector;
+ UChar Ist;
+ UChar Atrributes;
+
+ UShort SecondOffset;
+ UInt ThirdOffset;
+ UInt Zero;
+
+ operator bool() { return Offset != 0xFFFF; }
+};
+
+using InterruptDescriptorArray = Array<InterruptDescriptor, 256>;
+
+class SegmentDescriptor final {
+ public:
+ UInt16 Base;
+ UInt8 BaseMiddle;
+ UInt8 BaseHigh;
+
+ UShort Limit;
+ UChar Gran;
+ UChar AccessByte;
+};
+
+/***
+ * @brief Segment Boolean operations
+ */
+class SegmentDescriptorComparator final {
+ public:
+ Bool IsValid(SegmentDescriptor& seg) { return seg.Base > seg.Limit; }
+
+ Bool Equals(SegmentDescriptor& seg, SegmentDescriptor& segRight) {
+ return seg.Base == segRight.Base && seg.Limit == segRight.Limit;
+ }
+};
+
+using SegmentArray = Array<SegmentDescriptor, 6>;
+
+class GDTLoader final {
+ public:
+ static Void Load(Register64& gdt);
+ static Void Load(Ref<Register64>& gdt);
+};
+
+class IDTLoader final {
+ public:
+ static Void Load(Register64& idt);
+ static Void Load(Ref<Register64>& idt);
+};
+
+/***********************************************************************************/
+/// @brief Is the current config SMP aware?
+/// @return True if YES, False if not.
+/***********************************************************************************/
+
+Bool mp_is_smp(Void) noexcept;
+
+/***********************************************************************************/
+/// @brief Fetch and enable SMP scheduler.
+/// @param vendor_ptr SMP containing structure.
+/***********************************************************************************/
+Void mp_init_cores(VoidPtr vendor_ptr) noexcept;
+
+/***********************************************************************************/
+/// @brief Do a cpuid to check if MSR exists on CPU.
+/// @retval true it does exists.
+/// @retval false it doesn't.
+/***********************************************************************************/
+Bool hal_has_msr() noexcept;
+
+/***********************************************************************************/
+/// @brief Get Model specific register inside core.
+/// @param msr MSR
+/// @param lo low byte
+/// @param hi high byte
+/***********************************************************************************/
+Void hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) noexcept;
+
+/// @brief Set Model-specific register.
+/// @param msr MSR
+/// @param lo low byte
+/// @param hi high byte
+Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) noexcept;
+
+/// @brief Processor specific namespace.
+namespace Detail {
+ /* @brief TSS struct. */
+ struct NE_TSS final {
+ UInt32 fReserved1;
+ UInt64 fRsp0;
+ UInt64 fRsp1;
+ UInt64 fRsp2;
+ UInt64 fReserved2;
+ UInt64 fIst1;
+ UInt64 fIst2;
+ UInt64 fIst3;
+ UInt64 fIst4;
+ UInt64 fIst5;
+ UInt64 fIst6;
+ UInt64 fIst7;
+ UInt64 fReserved3;
+ UInt16 fReserved4;
+ UInt16 fIopb;
+ };
+
+ /**
+ @brief Global descriptor table entry, either null, code or data.
+ */
+
+ struct PACKED NE_GDT_ENTRY final {
+ UInt16 fLimitLow;
+ UInt16 fBaseLow;
+ UInt8 fBaseMid;
+ UInt8 fAccessByte;
+ UInt8 fFlags;
+ UInt8 fBaseHigh;
+ };
+} // namespace Detail
+
+class LAPICDmaWrapper final {
+ public:
+ explicit LAPICDmaWrapper(VoidPtr base);
+ ~LAPICDmaWrapper();
+
+ NE_COPY_DEFAULT(LAPICDmaWrapper)
+
+ public:
+ UInt32 Read(UInt16 reg) noexcept;
+ Void Write(UInt16 reg, UInt32 value) noexcept;
+
+ private:
+ VoidPtr fApic{nullptr};
+};
+
+/// @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 UInt8 rt_in8(UInt16 port);
+EXTERN_C UInt16 rt_in16(UInt16 port);
+EXTERN_C UInt32 rt_in32(UInt16 port);
+
+EXTERN_C Void rt_out16(UShort port, UShort byte);
+EXTERN_C Void rt_out8(UShort port, UChar byte);
+EXTERN_C Void rt_out32(UShort port, UInt byte);
+
+EXTERN_C Void rt_wait_400ns();
+EXTERN_C Void rt_halt();
+EXTERN_C Void rt_cli();
+EXTERN_C Void rt_sti();
+EXTERN_C Void rt_cld();
+EXTERN_C Void rt_std();
+
+EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virtual_address);
+
+EXTERN_C Int32 mm_memory_fence(VoidPtr virtual_address);
+} // namespace Kernel::HAL
+
+EXTERN_C Kernel::Void idt_handle_generic(Kernel::UIntPtr rsp);
+EXTERN_C Kernel::Void idt_handle_gpf(Kernel::UIntPtr rsp);
+EXTERN_C Kernel::Void idt_handle_math(Kernel::UIntPtr rsp);
+EXTERN_C Kernel::Void idt_handle_pf(Kernel::UIntPtr rsp);
+
+EXTERN_C ATTRIBUTE(naked) Kernel::Void hal_load_idt(Kernel::HAL::Register64 ptr);
+EXTERN_C ATTRIBUTE(naked) Kernel::Void hal_load_gdt(Kernel::HAL::Register64 ptr);
+
+inline Kernel::VoidPtr kKernelBitMpStart = nullptr;
+inline Kernel::UIntPtr kKernelBitMpSize = 0UL;
+
+#endif // __NE_AMD64__ */ \ No newline at end of file
diff --git a/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc
new file mode 100644
index 00000000..14b40b98
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc
@@ -0,0 +1,600 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+/**
+ * @file AHCI+Generic.cc
+ * @author Amlal El Mahrouss (amlal@nekernel.org)
+ * @brief AHCI Generic driver.
+ * @version 0.1
+ * @date 2024-02-02
+ *
+ * @copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+ *
+ */
+
+#include <DmaKit/DmaPool.h>
+#include <FirmwareKit/EPM.h>
+#include <KernelKit/DeviceMgr.h>
+#include <KernelKit/DriveMgr.h>
+#include <KernelKit/KPC.h>
+#include <KernelKit/LockDelegate.h>
+#include <KernelKit/PCI/Iterator.h>
+#include <KernelKit/ProcessScheduler.h>
+#include <KernelKit/Timer.h>
+#include <NeKit/Utils.h>
+#include <StorageKit/AHCI.h>
+#include <modules/AHCI/AHCI.h>
+#include <modules/ATA/ATA.h>
+
+#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 <BOOL Write, BOOL CommandOrCTRL, BOOL Identify>
+STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz,
+ SizeT size_buffer) noexcept;
+
+STATIC Int32 drv_find_cmd_slot_ahci(HbaPort* port) noexcept;
+
+STATIC Void drv_compute_disk_ahci() noexcept;
+
+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() noexcept {
+ kSATASectorCount = 0UL;
+
+ rt_set_memory(kIdentifyData, 0, kAHCISectorSize);
+
+ drv_std_input_output_ahci<NO, YES, YES>(0, kIdentifyData, kAHCISectorSize, kAHCISectorSize);
+
+ // --> Reinterpret the 512-byte buffer as an array of 256 UInt16 words
+ UInt16* identify_words = reinterpret_cast<UInt16*>(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) noexcept {
+ 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 <BOOL Write, BOOL CommandOrCTRL, BOOL Identify>
+STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz,
+ SizeT size_buffer) noexcept {
+ 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: Task File Error during 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) {
+ /// AMLALE: 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<YES, YES, NO>(lba, reinterpret_cast<UInt8*>(buffer), sector_sz,
+ size_buffer);
+}
+
+////////////////////////////////////////////////////
+///
+////////////////////////////////////////////////////
+Void drv_std_read(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) {
+ drv_std_input_output_ahci<NO, YES, NO>(lba, reinterpret_cast<UInt8*>(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(DeviceInterface<IMountpoint*>* 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<NO, YES, NO>(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(DeviceInterface<IMountpoint*>* 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<YES, YES, NO>(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<AHCIDeviceInterface> sk_acquire_ahci_device(UInt32 drv_index) {
+ if (!drv_std_detected_ahci()) return ErrorOr<AHCIDeviceInterface>(kErrorDisk);
+
+ AHCIDeviceInterface device(Detail::sk_io_read_ahci, Detail::sk_io_write_ahci);
+
+ device.SetPortsImplemented(kSATAPortsImplemented);
+ device.SetIndex(drv_index);
+
+ return ErrorOr<AHCIDeviceInterface>(device);
+}
+} // namespace Kernel
diff --git a/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc b/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc
new file mode 100644
index 00000000..cf6147d9
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Storage/DMA+Generic.cc
@@ -0,0 +1,199 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+/**
+ * @file DMA+Generic.cc
+ * @author Amlal El Mahrouss (amlal@nekernel.org)
+ * @brief ATA driver (DMA mode).
+ * @version 0.1
+ * @date 2024-02-02
+ *
+ * @copyright Copyright (c) Amlal El Mahrouss
+ *
+ */
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/PCI/Iterator.h>
+#include <modules/ATA/ATA.h>
+
+#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
new file mode 100644
index 00000000..88f95a86
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Storage/NVME+Generic.cc
@@ -0,0 +1,9 @@
+/* ========================================
+
+ Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#include <modules/NVME/NVME.h>
+
+using namespace Kernel;
diff --git a/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc
new file mode 100644
index 00000000..0516be39
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/Storage/PIO+Generic.cc
@@ -0,0 +1,278 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+/**
+ * @file PIO+Generic.cc
+ * @author Amlal El Mahrouss (amlal@nekernel.org)
+ * @brief ATA driver (PIO mode).
+ * @version 0.1
+ * @date 2024-02-02
+ *
+ * @copyright Copyright (c) Amlal El Mahrouss
+ *
+ */
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/DriveMgr.h>
+#include <StorageKit/ATA.h>
+#include <modules/ATA/ATA.h>
+
+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(DeviceInterface<IMountpoint*>* 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(DeviceInterface<IMountpoint*>* 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<ATADeviceInterface> 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<ATADeviceInterface>(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
new file mode 100644
index 00000000..0200ec5a
--- /dev/null
+++ b/src/kernel/HALKit/AMD64/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};