summaryrefslogtreecommitdiffhomepage
path: root/dev/kernel/HALKit/AMD64
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2025-03-23 19:13:48 +0100
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2025-03-23 19:15:17 +0100
commita13e1c0911c0627184bc38f18c7fdda64447b3ad (patch)
tree073a62c09bf216e85a3f310376640fa1805147f9 /dev/kernel/HALKit/AMD64
parent149fa096eb306d03686b3b67e813cf1a78e08cd0 (diff)
meta(kernel): Reworked repository's filesystem structure.
Removing useless parts of the project too. Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/kernel/HALKit/AMD64')
-rw-r--r--dev/kernel/HALKit/AMD64/CPUID.h86
-rw-r--r--dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc122
-rw-r--r--dev/kernel/HALKit/AMD64/HalAPICController.cc44
-rw-r--r--dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc271
-rw-r--r--dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s8
-rw-r--r--dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm77
-rw-r--r--dev/kernel/HALKit/AMD64/HalBoot.asm28
-rw-r--r--dev/kernel/HALKit/AMD64/HalCommonAPI.asm82
-rw-r--r--dev/kernel/HALKit/AMD64/HalControlRegister.s45
-rw-r--r--dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc245
-rw-r--r--dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc5
-rw-r--r--dev/kernel/HALKit/AMD64/HalDebugOutput.cc190
-rw-r--r--dev/kernel/HALKit/AMD64/HalDebugPort.cc42
-rw-r--r--dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc126
-rw-r--r--dev/kernel/HALKit/AMD64/HalInterruptAPI.asm402
-rw-r--r--dev/kernel/HALKit/AMD64/HalKernelMain.cc117
-rw-r--r--dev/kernel/HALKit/AMD64/HalKernelPanic.cc68
-rw-r--r--dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc204
-rw-r--r--dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc101
-rw-r--r--dev/kernel/HALKit/AMD64/HalRoutineWait.s11
-rw-r--r--dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc52
-rw-r--r--dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc7
-rw-r--r--dev/kernel/HALKit/AMD64/HalTimerAMD64.cc86
-rw-r--r--dev/kernel/HALKit/AMD64/HalUtils.asm26
-rw-r--r--dev/kernel/HALKit/AMD64/Hypervisor.h25
-rw-r--r--dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc7
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/DMA.cc87
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/Database.cc11
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/Device.cc171
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/Express.cc11
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/IO.cc7
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/Iterator.cc39
-rw-r--r--dev/kernel/HALKit/AMD64/PCI/PCI.cc7
-rw-r--r--dev/kernel/HALKit/AMD64/Paging.h99
-rw-r--r--dev/kernel/HALKit/AMD64/Processor.h326
-rw-r--r--dev/kernel/HALKit/AMD64/ReadMe.md8
-rw-r--r--dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc424
-rw-r--r--dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc253
-rw-r--r--dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc191
-rwxr-xr-xdev/kernel/HALKit/AMD64/make_ap_blob.sh3
40 files changed, 4114 insertions, 0 deletions
diff --git a/dev/kernel/HALKit/AMD64/CPUID.h b/dev/kernel/HALKit/AMD64/CPUID.h
new file mode 100644
index 00000000..7f04ac27
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/CPUID.h
@@ -0,0 +1,86 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+ File: CPUID.h
+ Purpose: CPUID flags.
+
+ Revision History:
+
+ 30/01/24: Added file (amlel)
+
+------------------------------------------- */
+
+#pragma once
+
+#include <NewKit/Defines.h>
+
+enum CPUFeatureEnum
+{
+ 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
+};
+
+namespace NeOS
+{
+ typedef Int64 CPUID;
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc b/dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc
new file mode 100644
index 00000000..f327dc3f
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc
@@ -0,0 +1,122 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <HALKit/AMD64/Processor.h>
+#include <NewKit/KString.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/MemoryMgr.h>
+
+namespace NeOS
+{
+ 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()
+ {
+ failed_to_shutdown:
+ return NO;
+ }
+
+ /// @brief Reboot machine in either ACPI or by triple faulting.
+ /// @return nothing it's a reboot.
+ Void ACPIFactoryInterface::Reboot()
+ {
+ failed_to_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 NeOS
diff --git a/dev/kernel/HALKit/AMD64/HalAPICController.cc b/dev/kernel/HALKit/AMD64/HalAPICController.cc
new file mode 100644
index 00000000..a4de5091
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalAPICController.cc
@@ -0,0 +1,44 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <HALKit/AMD64/Processor.h>
+
+#define cIOAPICRegVal (4)
+#define cIOAPICRegReg (0)
+
+namespace NeOS::HAL
+{
+ APICController::APICController(VoidPtr base)
+ : fApic(base)
+ {
+ }
+
+ /// @brief Read from APIC controller.
+ /// @param reg register.
+ UInt32 APICController::Read(UInt32 reg) noexcept
+ {
+ MUST_PASS(this->fApic);
+
+ UInt32 volatile* io_apic = (UInt32 volatile*)this->fApic;
+ io_apic[cIOAPICRegReg] = (reg & 0xFF);
+
+ return io_apic[cIOAPICRegVal];
+ }
+
+ /// @brief Write to APIC controller.
+ /// @param reg register.
+ /// @param value value.
+ Void APICController::Write(UInt32 reg, UInt32 value) noexcept
+ {
+ MUST_PASS(this->fApic);
+
+ UInt32 volatile* io_apic = (UInt32 volatile*)this->fApic;
+
+ io_apic[cIOAPICRegReg] = (reg & 0xFF);
+ io_apic[cIOAPICRegVal] = value;
+ }
+} // namespace NeOS::HAL
diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
new file mode 100644
index 00000000..da680afa
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
@@ -0,0 +1,271 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <KernelKit/UserProcessScheduler.h>
+#include <HALKit/AMD64/Processor.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/BinaryMutex.h>
+#include <KernelKit/UserProcessScheduler.h>
+#include <KernelKit/Timer.h>
+#include <modules/CoreGfx/TextMgr.h>
+#include <NewKit/KernelPanic.h>
+#include <KernelKit/HardwareThreadScheduler.h>
+
+#define kApicSignature "APIC"
+
+#define kAPIC_ICR_Low 0x300
+#define kAPIC_ICR_High 0x310
+#define kAPIC_SIPI_Vector 0x00500
+#define kAPIC_EIPI_Vector 0x00400
+
+#define kAPIC_BASE_MSR 0x1B
+#define kAPIC_BASE_MSR_BSP 0x100
+#define kAPIC_BASE_MSR_ENABLE 0x800
+
+/// @note: _hal_switch_context is internal
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+//! NOTE: fGSI stands 'Field Global System Interrupt'
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+namespace NeOS::HAL
+{
+ struct PROCESS_APIC_MADT;
+ struct PROCESS_CONTROL_BLOCK;
+
+ struct PROCESS_CONTROL_BLOCK final
+ {
+ HAL::StackFramePtr mFrame;
+ };
+
+ STATIC struct PROCESS_APIC_MADT* kMADTBlock = nullptr;
+ STATIC Bool kSMPAware = false;
+ STATIC Int64 kSMPCount = 0;
+
+ STATIC UIntPtr kApicBaseAddress = 0UL;
+
+ STATIC Int32 kSMPInterrupt = 0;
+ STATIC UInt64 kAPICLocales[kSchedProcessLimitPerTeam] = {0};
+ STATIC VoidPtr kRawMADT = nullptr;
+
+ /// @brief Multiple APIC Descriptor Table.
+ struct PROCESS_APIC_MADT final SDT_OBJECT
+ {
+ UInt32 Address; // Madt address
+ UInt8 Flags; // Madt flags
+
+ struct
+ {
+ UInt8 Type;
+ UInt8 Len;
+
+ union {
+ struct
+ {
+ UInt8 IoID;
+ UInt8 Zero;
+ UInt32 IoAddress;
+ UInt32 GISBase;
+ } IOAPIC;
+
+ struct
+ {
+ UInt8 Source;
+ UInt8 IRQSource;
+ UInt32 GSI;
+ UInt16 Flags;
+ } LApicNMI;
+
+ struct
+ {
+ UInt8 ProcessorID;
+ UInt16 Flags;
+ UInt8 LINT;
+ } LAPIC;
+
+ struct
+ {
+ UInt16 Reserved;
+ UInt64 Address;
+ } LApicOverride;
+
+ struct
+ {
+ UInt16 Reserved;
+ UInt32 x2APICID;
+ UInt32 Flags;
+ UInt32 AcpiID;
+ } LApic;
+ };
+ } List[]; // Records List
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ /***********************************************************************************/
+ /// @brief Send IPI command to APIC.
+ /// @param apic_id programmable interrupt controller id.
+ /// @param vector vector interrupt.
+ /// @param target target APIC adress.
+ /// @return
+ /***********************************************************************************/
+
+ Void hal_send_start_ipi(UInt32 target, UInt32 apic_id)
+ {
+ NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_High, apic_id << 24);
+ NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_Low, 0x00000500 | 0x00004000 | 0x00000000);
+
+ while (NeOS::ke_dma_read<UInt32>(target, kAPIC_ICR_Low) & 0x1000)
+ {
+ ;
+ }
+ }
+
+ /***********************************************************************************/
+ /// @brief Send end IPI for CPU.
+ /// @param apic_id
+ /// @param vector
+ /// @param target
+ /// @return
+ /***********************************************************************************/
+ Void hal_send_sipi(UInt32 target, UInt32 apic_id, UInt8 vector)
+ {
+ NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_High, apic_id << 24);
+ NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_Low, 0x00000600 | 0x00004000 | 0x00000000 | vector);
+
+ while (NeOS::ke_dma_read<UInt32>(target, kAPIC_ICR_Low) & 0x1000)
+ {
+ NE_UNUSED(0);
+ }
+ }
+
+ STATIC PROCESS_CONTROL_BLOCK kProcessBlocks[kSchedProcessLimitPerTeam] = {0};
+
+ EXTERN_C HAL::StackFramePtr mp_get_current_context(Int64 pid)
+ {
+ const auto process_index = pid % kSchedProcessLimitPerTeam;
+ return kProcessBlocks[process_index].mFrame;
+ }
+
+ EXTERN_C BOOL mp_register_process(HAL::StackFramePtr stack_frame, ProcessID pid)
+ {
+ MUST_PASS(stack_frame);
+
+ const auto process_index = pid % kSchedProcessLimitPerTeam;
+
+ kProcessBlocks[process_index].mFrame = stack_frame;
+
+ auto first_id = kAPICLocales[0];
+
+ hal_send_sipi(kApicBaseAddress, first_id, (UInt8)(((UIntPtr)stack_frame->BP) >> 12));
+
+ 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 Assembly symbol to bootstrap AP.
+ /***********************************************************************************/
+ EXTERN_C Char* hal_ap_blob_start;
+
+ /***********************************************************************************/
+ /// @brief Assembly symbol to bootstrap AP.
+ /***********************************************************************************/
+ EXTERN_C Char* hal_ap_blob_end;
+
+ /***********************************************************************************/
+ /// @brief Fetch and enable SMP scheduler.
+ /// @param vendor_ptr SMP containing structure.
+ /***********************************************************************************/
+ Void mp_get_cores(VoidPtr vendor_ptr) noexcept
+ {
+ if (!vendor_ptr)
+ return;
+
+ if (!kHandoverHeader->f_HardwareTables.f_MultiProcessingEnabled)
+ {
+ kSMPAware = NO;
+ return;
+ }
+
+ auto hw_and_pow_int = PowerFactoryInterface(vendor_ptr);
+ kRawMADT = hw_and_pow_int.Find(kApicSignature).Leak().Leak();
+
+ kMADTBlock = reinterpret_cast<PROCESS_APIC_MADT*>(kRawMADT);
+ kSMPAware = NO;
+
+ if (kMADTBlock)
+ {
+ SizeT index = 0;
+
+ kSMPInterrupt = 0;
+ kSMPCount = 0;
+
+ kout << "SMP: Starting APs...\r";
+
+ UInt32 eax, edx;
+ kApicBaseAddress = kMADTBlock->Address;
+
+ while (Yes)
+ {
+ if (kMADTBlock->List[index].Type > 9 ||
+ kSMPCount > kSchedProcessLimitPerTeam)
+ break;
+
+ switch (kMADTBlock->List[index].Type)
+ {
+ case 0x00: {
+ if (kMADTBlock->List[kSMPCount].LAPIC.ProcessorID < 1)
+ break;
+
+ kAPICLocales[kSMPCount] = kMADTBlock->List[kSMPCount].LAPIC.ProcessorID;
+ kout << "SMP: APIC ID: " << number(kAPICLocales[kSMPCount]) << kendl;
+
+ // I'll just make the AP start from scratch here.
+
+ hal_send_start_ipi(kApicBaseAddress, kAPICLocales[kSMPCount]);
+
+ HardwareTimer timer(NeOS::rtl_ms(10));
+ timer.Wait();
+
+ /// TODO: HAL helper to create an address.
+
+ hal_send_sipi(kApicBaseAddress, kAPICLocales[kSMPCount], (UInt8)(((UIntPtr)hal_ap_blob_start) >> 12));
+
+ ++kSMPCount;
+ break;
+ }
+ default:
+ break;
+ }
+
+ ++index;
+ }
+
+ kout << "SMP: number of APs: " << number(kSMPCount) << kendl;
+
+ // Kernel is now SMP aware.
+ // That means that the scheduler is now available (on MP Kernels)
+
+ kSMPAware = true;
+
+ /// TODO: Notify Boot AP that it must start.
+ }
+ }
+} // namespace NeOS::HAL
+
+///////////////////////////////////////////////////////////////////////////////////////
diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s b/dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s
new file mode 100644
index 00000000..a8ad3b76
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s
@@ -0,0 +1,8 @@
+.data
+
+.global hal_ap_blob_start /* Export the start symbol */
+.global hal_ap_blob_end /* Export the end symbol */
+
+hal_ap_blob_start:
+ .incbin "HALKit/AMD64/HalApplicationProcessorStartup.bin"
+hal_ap_blob_end:
diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm b/dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm
new file mode 100644
index 00000000..c64e0a09
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm
@@ -0,0 +1,77 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+;; *
+;; * ========================================================
+;; */
+
+[bits 16]
+[org 0x7c000]
+
+hal_ap_start:
+ mov ax, 0x0
+ mov ss, ax
+ mov esp, 0x7000
+
+ cli
+ mov eax, cr0
+ or eax, 1
+ mov cr0, eax
+ jmp .hal_ap_start_flush
+.hal_ap_start_flush:
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov eax, cr4
+ or eax, 1 << 5
+ mov cr4, eax
+
+ mov eax, cr3
+ mov cr3, eax
+
+ mov ecx, 0xC0000080
+ rdmsr
+ or eax, 1
+ wrmsr
+
+ mov eax, cr0
+ or eax, (1 << 31)
+ mov cr0, eax
+
+ jmp 0x08:hal_ap_64bit_entry
+hal_ap_end:
+
+hal_ap_length:
+ dq hal_ap_end - hal_ap_start
+
+[bits 64]
+
+hal_ap_64bit_entry:
+ mov ax, 0x23
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov rsp, [hal_ap_64bit_entry_stack_end]
+
+ push 0x33
+ push qword [hal_ap_64bit_entry_loop]
+ o64 pushf
+ push rsp
+ push 0x33
+
+ o64 iret
+
+hal_ap_64bit_entry_loop:
+ jmp $
+
+hal_ap_64bit_entry_stack:
+ resb 8196*2
+hal_ap_64bit_entry_stack_end: \ No newline at end of file
diff --git a/dev/kernel/HALKit/AMD64/HalBoot.asm b/dev/kernel/HALKit/AMD64/HalBoot.asm
new file mode 100644
index 00000000..3ccdd50e
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalBoot.asm
@@ -0,0 +1,28 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+;; *
+;; * ========================================================
+;; */
+
+[bits 64]
+
+;; Global symbol of this unit
+[extern hal_init_platform]
+
+%define kTypeKernel 100
+%define kArchAmd64 122
+%define kHandoverMagic 0xBADCC
+
+section .ldr
+
+HandoverMagic:
+ dq kHandoverMagic
+HandoverType:
+ dw kTypeKernel
+HandoverPad:
+ dw 0
+HandoverArch:
+ dw kArchAmd64
diff --git a/dev/kernel/HALKit/AMD64/HalCommonAPI.asm b/dev/kernel/HALKit/AMD64/HalCommonAPI.asm
new file mode 100644
index 00000000..671a955b
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalCommonAPI.asm
@@ -0,0 +1,82 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+;; *
+;; * ========================================================
+;; */
+
+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 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
+
+ o64 sysret
+
+[bits 16]
diff --git a/dev/kernel/HALKit/AMD64/HalControlRegister.s b/dev/kernel/HALKit/AMD64/HalControlRegister.s
new file mode 100644
index 00000000..b94744f5
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalControlRegister.s
@@ -0,0 +1,45 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+.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/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc
new file mode 100644
index 00000000..9eaa24eb
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc
@@ -0,0 +1,245 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/UserProcessScheduler.h>
+#include <NewKit/KString.h>
+#include <SignalKit/Signals.h>
+
+STATIC BOOL kIsScheduling = NO;
+
+/// @brief Handle GPF fault.
+/// @param rsp
+EXTERN_C void idt_handle_gpf(NeOS::UIntPtr rsp)
+{
+ auto process = NeOS::UserProcessScheduler::The().CurrentProcess();
+
+ if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning)
+ return;
+
+ kIsScheduling = NO;
+
+ kout << "Kernel: General Protection Fault.\r";
+
+ process.Leak().ProcessSignal.SignalArg = rsp;
+ process.Leak().ProcessSignal.SignalID = SIGKILL;
+ process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status;
+
+ kout << "Kernel: SIGKILL status.\r";
+
+ process.Leak().Status = NeOS::ProcessStatusKind::kKilled;
+
+ process.Leak().Crash();
+}
+
+/// @brief Handle page fault.
+/// @param rsp
+EXTERN_C void idt_handle_pf(NeOS::UIntPtr rsp)
+{
+ auto process = NeOS::UserProcessScheduler::The().CurrentProcess();
+
+ if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning)
+ return;
+
+ kIsScheduling = NO;
+
+ kout << "Kernel: Page Fault.\r";
+ kout << "Kernel: SIGKILL\r";
+
+ process.Leak().ProcessSignal.SignalArg = rsp;
+ process.Leak().ProcessSignal.SignalID = SIGKILL;
+ process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status;
+
+ process.Leak().Status = NeOS::ProcessStatusKind::kKilled;
+
+ process.Leak().Crash();
+}
+
+namespace NeOS::Detail
+{
+ constexpr static Int32 kTimeoutCount = 100000UL;
+}
+
+/// @brief Handle scheduler interrupt.
+EXTERN_C void idt_handle_scheduler(NeOS::UIntPtr rsp)
+{
+ static NeOS::Int64 try_count_before_brute = NeOS::Detail::kTimeoutCount;
+
+ while (kIsScheduling)
+ {
+ --try_count_before_brute;
+
+ if (try_count_before_brute < 1)
+ break;
+ }
+
+ try_count_before_brute = NeOS::Detail::kTimeoutCount;
+ kIsScheduling = YES;
+
+ NeOS::UserProcessHelper::StartScheduling();
+
+ kIsScheduling = NO;
+}
+
+/// @brief Handle math fault.
+/// @param rsp
+EXTERN_C void idt_handle_math(NeOS::UIntPtr rsp)
+{
+ auto process = NeOS::UserProcessScheduler::The().CurrentProcess();
+
+ if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning)
+ return;
+
+ kIsScheduling = NO;
+
+ kout << "Kernel: Math error (division by zero?).\r";
+
+ process.Leak().ProcessSignal.SignalArg = rsp;
+ process.Leak().ProcessSignal.SignalID = SIGKILL;
+ process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status;
+
+ kout << "Kernel: SIGKILL status.\r";
+
+ process.Leak().Status = NeOS::ProcessStatusKind::kKilled;
+
+ process.Leak().Crash();
+}
+
+/// @brief Handle any generic fault.
+/// @param rsp
+EXTERN_C void idt_handle_generic(NeOS::UIntPtr rsp)
+{
+ auto process = NeOS::UserProcessScheduler::The().CurrentProcess();
+
+ if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning)
+ {
+ kout << "Getting here.\r";
+ return;
+ }
+
+ kIsScheduling = NO;
+
+ kout << "Kernel: Generic Process Fault.\r";
+
+ process.Leak().ProcessSignal.SignalArg = rsp;
+ process.Leak().ProcessSignal.SignalID = SIGKILL;
+ process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status;
+
+ kout << "Kernel: SIGKILL status.\r";
+
+ process.Leak().Status = NeOS::ProcessStatusKind::kKilled;
+
+ process.Leak().Crash();
+}
+
+EXTERN_C NeOS::Void idt_handle_breakpoint(NeOS::UIntPtr rip)
+{
+ auto process = NeOS::UserProcessScheduler::The().CurrentProcess();
+
+ if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning)
+ {
+ kout << "Kernel: SIGTRAP\r";
+
+ while (YES)
+ ;
+ }
+
+ kIsScheduling = NO;
+
+ kout << "Kernel: Process RIP: " << NeOS::hex_number(rip) << kendl;
+ kout << "Kernel: SIGTRAP\r";
+
+ process.Leak().ProcessSignal.SignalArg = rip;
+ process.Leak().ProcessSignal.SignalID = SIGTRAP;
+
+ process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status;
+
+ kout << "Kernel: SIGTRAP status.\r";
+
+ process.Leak().Status = NeOS::ProcessStatusKind::kFrozen;
+}
+
+/// @brief Handle #UD fault.
+/// @param rsp
+EXTERN_C void idt_handle_ud(NeOS::UIntPtr rsp)
+{
+ auto process = NeOS::UserProcessScheduler::The().CurrentProcess();
+
+ if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning)
+ return;
+
+ kIsScheduling = NO;
+
+ kout << "Kernel: Undefined Opcode.\r";
+
+ process.Leak().ProcessSignal.SignalArg = rsp;
+ process.Leak().ProcessSignal.SignalID = SIGKILL;
+ process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status;
+
+ kout << "Kernel: SIGKILL status.\r";
+
+ process.Leak().Status = NeOS::ProcessStatusKind::kKilled;
+
+ process.Leak().Crash();
+}
+
+/// @brief Enter syscall from assembly.
+/// @param stack the stack pushed from assembly routine.
+/// @return nothing.
+EXTERN_C NeOS::Void hal_system_call_enter(NeOS::UIntPtr rcx_syscall_index, NeOS::UIntPtr rdx_syscall_struct)
+{
+ if (rcx_syscall_index < kSyscalls.Count())
+ {
+ kout << "syscall: Enter Syscall.\r";
+
+ if (kSyscalls[rcx_syscall_index].fHooked)
+ {
+ if (kSyscalls[rcx_syscall_index].fProc)
+ {
+ (kSyscalls[rcx_syscall_index].fProc)((NeOS::VoidPtr)rdx_syscall_struct);
+ }
+ else
+ {
+ kout << "syscall: syscall isn't valid at all! (is nullptr)\r";
+ }
+ }
+ else
+ {
+ kout << "syscall: syscall isn't hooked at all! (is set to false)\r";
+ }
+
+ kout << "syscall: Exit Syscall.\r";
+ }
+}
+
+/// @brief Enter Kernel call from assembly (DDK only).
+/// @param stack the stack pushed from assembly routine.
+/// @return nothing.
+EXTERN_C NeOS::Void hal_kernel_call_enter(NeOS::UIntPtr rcx_kerncall_index, NeOS::UIntPtr rdx_kerncall_struct)
+{
+ if (rcx_kerncall_index < kKerncalls.Count())
+ {
+ kout << "kerncall: Enter Kernel Call List.\r";
+
+ if (kKerncalls[rcx_kerncall_index].fHooked)
+ {
+ if (kKerncalls[rcx_kerncall_index].fProc)
+ {
+ (kKerncalls[rcx_kerncall_index].fProc)((NeOS::VoidPtr)rdx_kerncall_struct);
+ }
+ else
+ {
+ kout << "kerncall: Kernel call isn't valid at all! (is nullptr)\r";
+ }
+ }
+ else
+ {
+ kout << "kerncall: Kernel call isn't hooked at all! (is set to false)\r";
+ }
+
+ kout << "kerncall: Exit Kernel Call List.\r";
+ }
+}
diff --git a/dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc b/dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc
new file mode 100644
index 00000000..75eb1f15
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc
@@ -0,0 +1,5 @@
+/* -------------------------------------------
+
+ Copyright (C) 2025, Amlal EL Mahrouss, all rights reserved.
+
+ ------------------------------------------- */
diff --git a/dev/kernel/HALKit/AMD64/HalDebugOutput.cc b/dev/kernel/HALKit/AMD64/HalDebugOutput.cc
new file mode 100644
index 00000000..2bc89a5e
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalDebugOutput.cc
@@ -0,0 +1,190 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/DebugOutput.h>
+#include <NewKit/Utils.h>
+#include <NewKit/New.h>
+#include <modules/CoreGfx/FBMgr.h>
+#include <modules/CoreGfx/TextMgr.h>
+
+namespace NeOS
+{
+ enum CommStatus : UInt16
+ {
+ kStateInvalid,
+ kStateReady = 0xCF,
+ kStateTransmit = 0xFC,
+ kStateCnt = 3
+ };
+
+ namespace Detail
+ {
+ constexpr const UInt16 kPort = 0x3F8;
+ static UInt16 kState = kStateInvalid;
+
+ /// @brief Init COM1.
+ /// @return
+ template <Int16 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;
+
+ EXTERN_C void ke_io_write(IDeviceObject<const Char*>* obj, const Char* bytes)
+ {
+#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, 256U);
+
+ static int x = kFontSizeX, y = kFontSizeY;
+
+ static BOOL not_important = YES;
+
+ while (index < len)
+ {
+ if (bytes[index] == '\r')
+ HAL::rt_out8(Detail::kPort, '\r');
+
+ HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]);
+
+ char tmp_str[2];
+ tmp_str[0] = bytes[index];
+ tmp_str[1] = 0;
+
+ if (bytes[index] == '*')
+ {
+ if (not_important)
+ not_important = NO;
+ else
+ not_important = YES;
+
+ ++index;
+
+ continue;
+ }
+
+ fb_render_string(tmp_str, y, x, not_important ? RGB(0xff, 0xff, 0xff) : RGB(0x00, 0x00, 0xff));
+
+ if (bytes[index] == '\r')
+ {
+ y += kFontSizeY;
+ x = kFontSizeX;
+ }
+
+ x += kFontSizeX;
+
+ if (y > kHandoverHeader->f_GOP.f_Height)
+ {
+ y = kFontSizeY;
+
+ fb_init();
+
+ FBDrawInRegion(fb_get_clear_clr(), FB::UIAccessibilty::Height(), FB::UIAccessibilty::Width(),
+ 0, 0);
+
+ fb_clear();
+ }
+
+ ++index;
+ }
+
+ Detail::kState = kStateReady;
+#endif // __DEBUG__
+ }
+
+ EXTERN_C void ke_io_read(IDeviceObject<const Char*>*, const Char* 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(NeOS::ke_io_write, NeOS::ke_io_read);
+ return out;
+ }
+
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/AMD64/HalDebugPort.cc b/dev/kernel/HALKit/AMD64/HalDebugPort.cc
new file mode 100644
index 00000000..7eada646
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalDebugPort.cc
@@ -0,0 +1,42 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+//! @file DebuggerPort.cc
+//! @brief UART debug via packets.
+
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/DebugOutput.h>
+
+// after that we have start of additional data.
+
+namespace NeOS
+{
+ void rt_debug_listen(DebuggerPortHeader* theHook) noexcept
+ {
+ if (theHook == nullptr)
+ return;
+
+ for (UInt32 i = 0U; i < kDebugMaxPorts; ++i)
+ {
+ HAL::rt_out16(theHook->fPort[i], kDebugMag0);
+ HAL::rt_wait_400ns();
+
+ HAL::rt_out16(theHook->fPort[i], kDebugMag1);
+ HAL::rt_wait_400ns();
+
+ HAL::rt_out16(theHook->fPort[i], kDebugMag2);
+ HAL::rt_wait_400ns();
+
+ HAL::rt_out16(theHook->fPort[i], kDebugMag3);
+ HAL::rt_wait_400ns();
+
+ if (HAL::rt_in16(theHook->fPort[i]) != kDebugUnboundPort)
+ ++theHook->fPortCnt;
+
+ HAL::rt_wait_400ns();
+ }
+ }
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc b/dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc
new file mode 100644
index 00000000..154b11af
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc
@@ -0,0 +1,126 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <ArchKit/ArchKit.h>
+#include <HALKit/AMD64/Processor.h>
+
+#define kPITDefaultTicks (1000U)
+
+namespace NeOS::HAL
+{
+ namespace Detail
+ {
+ STATIC ::NeOS::Detail::AMD64::InterruptDescriptorAMD64
+ kInterruptVectorTable[kKernelIdtSize] = {};
+
+ STATIC void hal_set_irq_mask(UInt8 irql);
+ STATIC void hal_clear_irq_mask(UInt8 irql);
+
+ STATIC Void hal_enable_pit(UInt16 ticks) noexcept
+ {
+ if (ticks == 0)
+ ticks = kPITDefaultTicks;
+
+ // Configure PIT to receieve scheduler interrupts.
+
+ UInt16 kPITCommDivisor = kPITFrequency / ticks; // 100 Hz.
+
+ HAL::rt_out8(kPITControlPort, 0x36); // Command to PIT
+ HAL::rt_out8(kPITChannel0Port, kPITCommDivisor & 0xFF); // Send low byte
+ HAL::rt_out8(kPITChannel0Port, (kPITCommDivisor >> 8) & 0xFF); // Send high byte
+
+ hal_clear_irq_mask(32);
+ }
+
+ STATIC void hal_set_irq_mask(UInt8 irql)
+ {
+ UInt16 port;
+ UInt8 value;
+
+ if (irql < 8)
+ {
+ port = kPICData;
+ }
+ else
+ {
+ port = kPIC2Data;
+ irql -= 8;
+ }
+
+ value = rt_in8(port) | (1 << irql);
+ rt_out8(port, value);
+ }
+
+ STATIC void hal_clear_irq_mask(UInt8 irql)
+ {
+ UInt16 port;
+ UInt8 value;
+
+ if (irql < 8)
+ {
+ port = kPICData;
+ }
+ else
+ {
+ port = kPIC2Data;
+ irql -= 8;
+ }
+
+ value = rt_in8(port) & ~(1 << irql);
+ rt_out8(port, value);
+ }
+ } // namespace Detail
+
+ /// @brief Loads the provided Global Descriptor Table.
+ /// @param gdt
+ /// @return
+ Void GDTLoader::Load(RegisterGDT& gdt)
+ {
+ hal_load_gdt(gdt);
+ }
+
+ Void IDTLoader::Load(Register64& idt)
+ {
+ rt_cli();
+
+ const Int16 kPITTickForScheduler = kPITDefaultTicks;
+
+ volatile ::NeOS::UIntPtr** ptr_ivt = (volatile ::NeOS::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 = 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(::NeOS::Detail::AMD64::InterruptDescriptorAMD64) *
+ (kKernelIdtSize);
+
+ hal_load_idt(idt);
+
+ Detail::hal_enable_pit(kPITTickForScheduler);
+
+ rt_sti();
+ }
+
+ void GDTLoader::Load(Ref<RegisterGDT>& gdt)
+ {
+ GDTLoader::Load(gdt.Leak());
+ }
+
+ void IDTLoader::Load(Ref<Register64>& idt)
+ {
+ IDTLoader::Load(idt.Leak());
+ }
+} // namespace NeOS::HAL
diff --git a/dev/kernel/HALKit/AMD64/HalInterruptAPI.asm b/dev/kernel/HALKit/AMD64/HalInterruptAPI.asm
new file mode 100644
index 00000000..ffea6707
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalInterruptAPI.asm
@@ -0,0 +1,402 @@
+;; /*
+;; * ---------------------------------------------------
+;; *
+;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+;; *
+;; * 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:
+ cld
+
+ std
+
+ o64 iret
+%endmacro
+
+%macro IntNormal 1
+global __NE_INT_%1
+__NE_INT_%1:
+ cld
+
+ std
+
+ 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
+
+section .text
+
+__NE_INT_0:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_1:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_2:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ 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:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ push rcx
+ mov rcx, rsp
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_4:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_5:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ std
+
+ o64 iret
+
+;; Invalid opcode interrupt
+__NE_INT_6:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_7:
+ cld
+
+ mov al, 0x20
+ out 0x20, al
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+;; Invalid opcode interrupt
+__NE_INT_8:
+ cld
+
+ mov al, 0x20
+ out 0xA0, al
+ out 0x20, al
+
+ push rcx
+ call idt_handle_generic
+ pop rcx
+
+ std
+
+ o64 iret
+
+IntNormal 9
+IntExp 10
+IntExp 11
+
+IntExp 12
+
+__NE_INT_13:
+ cld
+
+ mov al, 0x20
+ out 0xA0, al
+ out 0x20, al
+
+ push rcx
+ call idt_handle_gpf
+ pop rcx
+
+ std
+
+ o64 iret
+
+__NE_INT_14:
+ cld
+
+ mov al, 0x20
+ out 0xA0, al
+ out 0x20, al
+
+ 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]
+
+__NE_INT_32:
+ cld
+
+ mov al, 0x20
+ out 0xA0, al
+ out 0x20, al
+
+ 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
+IntNormal 40
+
+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:
+ cld
+
+ mov al, 0x20
+ out 0xA0, al
+ out 0x20, al
+
+ push rax
+ mov rax, hal_system_call_enter
+
+ mov rcx, r8
+ mov rdx, r9
+
+ call rax
+ pop rax
+
+ std
+
+ o64 iret
+
+__NE_INT_51:
+ cld
+
+ mov al, 0x20
+ out 0xA0, al
+ out 0x20, al
+
+ push rax
+ mov rax, hal_kernel_call_enter
+
+ mov rcx, r8
+ mov rdx, r9
+
+ 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:
+ cld
+
+ 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
diff --git a/dev/kernel/HALKit/AMD64/HalKernelMain.cc b/dev/kernel/HALKit/AMD64/HalKernelMain.cc
new file mode 100644
index 00000000..543e267b
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalKernelMain.cc
@@ -0,0 +1,117 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <StorageKit/AHCI.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/UserProcessScheduler.h>
+#include <KernelKit/HardwareThreadScheduler.h>
+#include <KernelKit/CodeMgr.h>
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <NetworkKit/IPC.h>
+#include <CFKit/Property.h>
+#include <modules/CoreGfx/TextMgr.h>
+
+EXTERN_C NeOS::VoidPtr kInterruptVectorTable[];
+EXTERN_C NeOS::VoidPtr mp_user_switch_proc;
+EXTERN_C NeOS::Char mp_user_switch_proc_stack_begin[];
+
+STATIC NeOS::Void hal_init_scheduler_team()
+{
+ for (NeOS::SizeT i = 0U; i < NeOS::UserProcessScheduler::The().CurrentTeam().AsArray().Count(); ++i)
+ {
+ NeOS::UserProcessScheduler::The().CurrentTeam().AsArray()[i] = NeOS::UserProcess();
+ NeOS::UserProcessScheduler::The().CurrentTeam().AsArray()[i].Status = NeOS::ProcessStatusKind::kKilled;
+ }
+}
+
+STATIC NeOS::UInt64 hal_rdtsc_fn()
+{
+ NeOS::UInt32 lo, hi;
+ __asm__ volatile("rdtsc"
+ : "=a"(lo), "=d"(hi));
+
+ return ((NeOS::UInt64)hi << 32) | lo;
+}
+
+STATIC NeOS::UInt64 kStartTim, kEndTim;
+
+/// @brief Kernel init procedure.
+EXTERN_C void hal_init_platform(
+ NeOS::HEL::BootInfoHeader* handover_hdr)
+{
+ kStartTim = hal_rdtsc_fn();
+
+ kHandoverHeader = handover_hdr;
+
+ if (kHandoverHeader->f_Magic != kHandoverMagic &&
+ kHandoverHeader->f_Version != kHandoverVersion)
+ {
+ return;
+ }
+
+ hal_init_scheduler_team();
+
+ /************************************** */
+ /* INITIALIZE BIT MAP. */
+ /************************************** */
+
+ kKernelBitMpSize = kHandoverHeader->f_BitMapSize;
+ kKernelBitMpStart = reinterpret_cast<NeOS::VoidPtr>(
+ reinterpret_cast<NeOS::UIntPtr>(kHandoverHeader->f_BitMapStart));
+
+ /************************************** */
+ /* INITIALIZE GDT AND SEGMENTS. */
+ /************************************** */
+
+ STATIC CONST auto kGDTEntriesCount = 6;
+
+ /* GDT, mostly descriptors for user and kernel segments. */
+ STATIC NeOS::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
+ {.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
+ };
+
+ // Load memory descriptors.
+ NeOS::HAL::RegisterGDT gdt_reg;
+
+ gdt_reg.Base = reinterpret_cast<NeOS::UIntPtr>(kGDTArray);
+ gdt_reg.Limit = (sizeof(NeOS::HAL::Detail::NE_GDT_ENTRY) * kGDTEntriesCount) - 1;
+
+ FB::fb_clear_video();
+
+ //! GDT will load hal_read_init after it successfully loads the segments.
+ NeOS::HAL::GDTLoader gdt_loader;
+ gdt_loader.Load(gdt_reg);
+
+ NeOS::ke_panic(RUNTIME_CHECK_BOOTSTRAP);
+}
+
+EXTERN_C NeOS::Void hal_real_init(NeOS::Void) noexcept
+{
+ NeOS::NeFS::fs_init_nefs();
+
+ NeOS::HAL::mp_get_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr);
+
+ NeOS::HAL::Register64 idt_reg;
+
+ idt_reg.Base = (NeOS::UIntPtr)kInterruptVectorTable;
+
+ NeOS::HAL::IDTLoader idt_loader;
+
+ kEndTim = hal_rdtsc_fn();
+
+ kout << "Cycles Spent Before Userland: " << NeOS::number(kEndTim - kStartTim) << kendl;
+
+ idt_loader.Load(idt_reg);
+
+ while (YES)
+ {
+ continue;
+ }
+}
diff --git a/dev/kernel/HALKit/AMD64/HalKernelPanic.cc b/dev/kernel/HALKit/AMD64/HalKernelPanic.cc
new file mode 100644
index 00000000..f0595903
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalKernelPanic.cc
@@ -0,0 +1,68 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <NewKit/KernelPanic.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/Timer.h>
+#include <KernelKit/DebugOutput.h>
+#include <NewKit/KString.h>
+#include <FirmwareKit/Handover.h>
+#include <KernelKit/FileMgr.h>
+#include <modules/CoreGfx/FBMgr.h>
+#include <modules/CoreGfx/TextMgr.h>
+#include <NewKit/Utils.h>
+
+/* Each error code is attributed with an ID, which will prompt a string onto the
+ * screen. Wait for debugger... */
+
+namespace NeOS
+{
+ /// @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 NeOS::Int32& id, const Char* message)
+ {
+ fb_init();
+
+ auto panic_text = RGB(0xff, 0xff, 0xff);
+
+ auto y = 10;
+ auto x = 10;
+
+ kout << "Kernel_Panic_MSG: " << message << kendl;
+ kout << "Kernel_Panic_ID: " << hex_number(id) << kendl;
+ 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)
+ {
+ kout << "Kernel_Panic_File: " << file << kendl;
+ kout << "Kernel_Panic_Line: " << line << kendl;
+
+ ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed
+ }
+ }
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc b/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc
new file mode 100644
index 00000000..fe9f0421
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc
@@ -0,0 +1,204 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+ File: HalPagingMgr.cc
+ Purpose: Platform Paging Manager.
+
+------------------------------------------- */
+
+#include <HALKit/AMD64/Paging.h>
+#include <HALKit/AMD64/Processor.h>
+
+namespace NeOS::HAL
+{
+ typedef UInt32 PageTableIndex;
+
+ /***********************************************************************************/
+ /// \brief Page store type.
+ /***********************************************************************************/
+ struct NE_PAGE_STORE final
+ {
+ struct
+ {
+ PDE* fPde{nullptr};
+ PTE* fPte{nullptr};
+ VoidPtr fPAddr{nullptr};
+ } fInternalStore;
+
+ Bool fStoreOp{No}; // Store operation is in progress.
+
+ bool IsValidPage(PTE* pte)
+ {
+ return pte && pte->Present;
+ }
+
+ bool IsWRPage(PTE* pte)
+ {
+ return pte && pte->Wr;
+ }
+
+ bool IsUserPage(PTE* pte)
+ {
+ return pte && pte->User;
+ }
+
+ static NE_PAGE_STORE& The()
+ {
+ static NE_PAGE_STORE the;
+ return the;
+ }
+ };
+
+ /// @brief Go over the Page structure and find the address of *virtual_address*
+
+ UIntPtr hal_get_phys_address(VoidPtr virtual_address)
+ {
+ // Constants for table index bits
+ const UInt64 kPmlIndexMask = 0x1FFULL; // Mask for PML4, PDPT, PD, PT index (9 bits)
+ const UInt64 kPtIndexMask = 0xFFFULL; // Mask for page table index (12 bits)
+
+ UInt64 cr3 = (UInt64)hal_read_cr3();
+
+ NE_PAGE_STORE& page_store = NE_PAGE_STORE::The();
+
+ // Extract the indices from the virtual address
+ UInt64 pml4_index = ((UIntPtr)virtual_address >> 39) & kPmlIndexMask;
+ UInt64 pdpt_index = ((UIntPtr)virtual_address >> 30) & kPmlIndexMask;
+ UInt64 pd_index = ((UIntPtr)virtual_address >> 21) & kPmlIndexMask;
+ UInt64 pt_index = ((UIntPtr)virtual_address >> 12) & kPmlIndexMask;
+
+ page_store.fStoreOp = Yes;
+
+ const auto kPmlEntrySize = 8;
+
+ // Read the PML4 entry from memory
+ UInt64 pml4_base = cr3 & ~kPtIndexMask; // CR3 points to the PML4 table base, mask off lower bits
+ UInt64 pml4_entry = (pml4_base + pml4_index * kPmlEntrySize); // Each entry is 8 bytes
+
+ // Read the PDPT entry
+ UInt64 pdpt_base = pml4_entry & ~kPtIndexMask; // Get the PDPT base physical address
+ UInt64 pdpt_entry = (pdpt_base + pdpt_index * kPmlEntrySize);
+
+ // Read the PD entry
+ UInt64 pd_base = pdpt_entry & ~kPtIndexMask; // Get the Page Directory base physical address
+ UInt64 pd_entry = (pd_base + pd_index * kPmlEntrySize);
+
+ // Read the PT entry
+ UInt64 pt_base = pd_entry & ~kPtIndexMask; // Get the Page Table base physical address
+ UInt64 pt_entry = (pt_base + pt_index * kPmlEntrySize);
+
+ // Lastly, grab the pte entry.
+ NE_PDE* pde_struct = reinterpret_cast<NE_PDE*>(pt_base);
+
+ return pde_struct->fEntries[pt_entry]->PhysicalAddress;
+ }
+
+ /***********************************************************************************/
+ /// \brief Retrieve the page status of a PTE.
+ /// \param pte Page Table Entry pointer.
+ /***********************************************************************************/
+ STATIC Void mmi_page_status(PTE* pte)
+ {
+ kout << (pte->Present ? "Present" : "Not Present") << kendl;
+ kout << (pte->Wr ? "W/R" : "Not W/R") << kendl;
+ kout << (pte->ExecDisable ? "NX" : "Not NX") << kendl;
+ kout << (pte->User ? "User" : "Not User") << kendl;
+ }
+
+ STATIC Int32 mmi_map_page_table_entry(UInt32 physical_address, UInt32 flags, NE_PTE* pt_entry, NE_PDE* pd_entry);
+
+ /***********************************************************************************/
+ /// @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)
+ {
+ // Constants for table index bits
+ const UInt64 kPmlIndexMask = 0x1FFULL; // Mask for PML4, PDPT, PD, PT index (9 bits)
+ const UInt64 kPtIndexMask = 0xFFFULL; // Mask for page table index (12 bits)
+
+ UInt64 cr3 = (UInt64)hal_read_cr3();
+
+ NE_PAGE_STORE& page_store = NE_PAGE_STORE::The();
+
+ // Extract the indices from the virtual address
+ UInt64 pml4_index = ((UIntPtr)virtual_address >> 39) & kPmlIndexMask;
+ UInt64 pdpt_index = ((UIntPtr)virtual_address >> 30) & kPmlIndexMask;
+ UInt64 pd_index = ((UIntPtr)virtual_address >> 21) & kPmlIndexMask;
+ UInt64 pt_index = ((UIntPtr)virtual_address >> 12) & kPmlIndexMask;
+
+ page_store.fStoreOp = Yes;
+
+ const auto kPmlEntrySize = 8;
+
+ // Read the PML4 entry from memory
+ UInt64 pml4_base = cr3 & ~kPtIndexMask; // CR3 points to the PML4 table base, mask off lower bits
+ UInt64 pml4_entry = (pml4_base + pml4_index * kPmlEntrySize); // Each entry is 8 bytes
+
+ // Read the PDPT entry
+ UInt64 pdpt_base = pml4_entry & ~kPtIndexMask; // Get the PDPT base physical address
+ UInt64 pdpt_entry = (pdpt_base + pdpt_index * kPmlEntrySize);
+
+ // Read the PD entry
+ UInt64 pd_base = pdpt_entry & ~kPtIndexMask; // Get the Page Directory base physical address
+ UInt64 pd_entry = (pd_base + pd_index * kPmlEntrySize);
+
+ // Read the PT entry
+ UInt64 pt_base = pd_entry & ~kPtIndexMask; // Get the Page Table base physical address
+ UInt64 pt_entry = (pt_base + pt_index * kPmlEntrySize);
+
+ // Lastly, grab the pte entry.
+ NE_PDE* pde_struct = reinterpret_cast<NE_PDE*>(pt_base);
+
+ return mmi_map_page_table_entry((UInt32)(UInt64)physical_address, flags, pde_struct->fEntries[pt_entry], pde_struct);
+ }
+
+ /***********************************************************************************/
+ /// @brief Maps flags for a specific pte.
+ /// @internal Internal function.
+ /***********************************************************************************/
+ STATIC Int32 mmi_map_page_table_entry(UInt32 physical_address, UInt32 flags, NE_PTE* pt_entry, NE_PDE* pd_entry)
+ {
+ if (!pt_entry)
+ return 1;
+
+ pt_entry->Present = true;
+
+ if (flags & kMMFlagsWr)
+ pt_entry->Wr = true;
+ else if (flags & ~kMMFlagsWr)
+ pt_entry->Wr = false;
+
+ if (flags & kMMFlagsNX)
+ pt_entry->ExecDisable = true;
+ else if (flags & ~kMMFlagsNX)
+ pt_entry->ExecDisable = false;
+
+ if (flags & kMMFlagsUser)
+ pt_entry->User = true;
+ else if (flags & ~kMMFlagsUser)
+ pt_entry->User = false;
+
+ pt_entry->PhysicalAddress = physical_address;
+
+ hal_invl_tlb(reinterpret_cast<VoidPtr>(pt_entry));
+
+ mmi_page_status(pt_entry);
+
+ NE_PAGE_STORE& page_store = NE_PAGE_STORE::The();
+
+ // Update Internal store.
+
+ page_store.fInternalStore.fPde = pd_entry;
+ page_store.fInternalStore.fPte = pt_entry;
+ page_store.fInternalStore.fPAddr = (VoidPtr)(UIntPtr)physical_address;
+
+ page_store.fStoreOp = No;
+
+ return 0;
+ }
+} // namespace NeOS::HAL
diff --git a/dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc b/dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc
new file mode 100644
index 00000000..b3da8352
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc
@@ -0,0 +1,101 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+ 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 NeOS::HAL
+{
+ Void lrt_out8(UInt16 port, UInt8 value)
+ {
+ asm volatile("outb %%al, %1"
+ :
+ : "a"(value), "Nd"(port)
+ : "memory");
+ }
+
+ Void lrt_out16(UInt16 port, UInt16 value)
+ {
+ asm volatile("outw %%ax, %1"
+ :
+ : "a"(value), "Nd"(port)
+ : "memory");
+ }
+
+ Void lrt_out32(UInt16 port, UInt32 value)
+ {
+ asm volatile("outl %%eax, %1"
+ :
+ : "a"(value), "Nd"(port)
+ : "memory");
+ }
+
+ UInt8 lrt_in8(UInt16 port)
+ {
+ UInt8 value = 0UL;
+ asm volatile("inb %1, %%al"
+ : "=a"(value)
+ : "Nd"(port)
+ : "memory");
+
+ return value;
+ }
+
+ UInt16 lrt_in16(UInt16 port)
+ {
+ UInt16 value = 0UL;
+ asm volatile("inw %1, %%ax"
+ : "=a"(value)
+ : "Nd"(port)
+ : "memory");
+
+ return value;
+ }
+
+ UInt32 lrt_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 NeOS::HAL
diff --git a/dev/kernel/HALKit/AMD64/HalRoutineWait.s b/dev/kernel/HALKit/AMD64/HalRoutineWait.s
new file mode 100644
index 00000000..89051ba4
--- /dev/null
+++ b/dev/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/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc b/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc
new file mode 100644
index 00000000..bf4b9d91
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc
@@ -0,0 +1,52 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/AMD64/Processor.h>
+#include <KernelKit/UserProcessScheduler.h>
+
+namespace NeOS
+{
+ /***********************************************************************************/
+ /// @brief Unimplemented function (crashes by default)
+ /// @param
+ /***********************************************************************************/
+
+ EXTERN_C Void __zka_pure_call(UserProcess* process)
+ {
+ if (process)
+ process->Crash();
+ }
+
+ /***********************************************************************************/
+ /// @brief Validate user stack.
+ /// @param stack_ptr the frame pointer.
+ /***********************************************************************************/
+
+ EXTERN_C Bool hal_check_stack(HAL::StackFramePtr stack_ptr)
+ {
+ if (!stack_ptr)
+ return No;
+
+ return stack_ptr->SP != 0 && stack_ptr->BP != 0;
+ }
+
+ /// @brief Wakes up thread.
+ /// Wakes up thread from the hang state.
+ Void mp_wakeup_thread(HAL::StackFrame* stack)
+ {
+ NeOS::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)
+ {
+ while (Yes)
+ {
+ /* Nothing to do, code is spinning */
+ }
+ }
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc b/dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc
new file mode 100644
index 00000000..e4e9daab
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc
@@ -0,0 +1,7 @@
+/* -------------------------------------------
+
+ Copyright (C) 2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <ArchKit/ArchKit.h>
diff --git a/dev/kernel/HALKit/AMD64/HalTimerAMD64.cc b/dev/kernel/HALKit/AMD64/HalTimerAMD64.cc
new file mode 100644
index 00000000..53386d36
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalTimerAMD64.cc
@@ -0,0 +1,86 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+ File: HalTimer.cc
+ Purpose: HAL timer
+
+ Revision History:
+
+ 07/07/24: Added file (amlel)
+
+------------------------------------------- */
+
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/Timer.h>
+
+// timer slot 0
+
+#define cHPETCounterRegValue (0x00)
+#define cHPETConfigRegValue (0x20)
+#define cHPETCompRegValue (0x24)
+#define cHPETInterruptRegValue (0x2C)
+
+///! BUGS: 0
+///! @file HalTimer.cc
+///! @brief Hardware Timer (HPET)
+
+namespace NeOS::Detail
+{
+ struct HPET_BLOCK : public NeOS::SDT
+ {
+ NeOS::UInt8 hardware_rev_id;
+ NeOS::UInt8 comparator_count : 5;
+ NeOS::UInt8 counter_size : 1;
+ NeOS::UInt8 reserved : 1;
+ NeOS::UInt8 legacy_replacement : 1;
+ NeOS::UInt16 pci_vendor_id;
+ ACPI_ADDRESS address;
+ NeOS::UInt8 hpet_number;
+ NeOS::UInt16 minimum_tick;
+ NeOS::UInt8 page_protection;
+ } PACKED;
+} // namespace NeOS::Detail
+
+using namespace NeOS;
+
+HardwareTimer::HardwareTimer(Int64 ms)
+ : fWaitFor(ms)
+{
+ auto power = PowerFactoryInterface(kHandoverHeader->f_HardwareTables.f_VendorPtr);
+
+ auto hpet = (Detail::HPET_BLOCK*)power.Find("HPET").Leak().Leak();
+ MUST_PASS(hpet);
+
+ fDigitalTimer = (IntPtr*)hpet->address.Address;
+}
+
+HardwareTimer::~HardwareTimer()
+{
+ fDigitalTimer = nullptr;
+ fWaitFor = 0;
+}
+
+BOOL HardwareTimer::Wait() noexcept
+{
+ if (fWaitFor < 1)
+ return NO;
+
+ // if not enabled yet.
+ if (!(*(fDigitalTimer + cHPETConfigRegValue) & (1 << 0)))
+ {
+ *(fDigitalTimer + cHPETConfigRegValue) |= (1 << 0); // enable it
+ *(fDigitalTimer + cHPETConfigRegValue) |= (1 << 3); // one shot conf
+ }
+
+ UInt64 ticks = fWaitFor / ((*(fDigitalTimer) >> 32) & __UINT32_MAX__);
+ UInt64 prev = *(fDigitalTimer + cHPETCounterRegValue);
+
+ prev += ticks;
+
+ while (*(fDigitalTimer + cHPETCounterRegValue) < (ticks))
+ ;
+
+ return YES;
+}
diff --git a/dev/kernel/HALKit/AMD64/HalUtils.asm b/dev/kernel/HALKit/AMD64/HalUtils.asm
new file mode 100644
index 00000000..83453714
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/HalUtils.asm
@@ -0,0 +1,26 @@
+;; /*
+;; * ========================================================
+;; *
+;; * NeKernel
+;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+;; *
+;; * ========================================================
+;; */
+
+[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
+
+;; //////////////////////////////////////////////////// ;;
+
+[extern kApicMadtAddressesCount]
diff --git a/dev/kernel/HALKit/AMD64/Hypervisor.h b/dev/kernel/HALKit/AMD64/Hypervisor.h
new file mode 100644
index 00000000..4c226eee
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/Hypervisor.h
@@ -0,0 +1,25 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#pragma once
+
+#include <NewKit/Defines.h>
+
+namespace NeOS
+{
+ 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 NeOS
diff --git a/dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc b/dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc
new file mode 100644
index 00000000..09632bc9
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc
@@ -0,0 +1,7 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <modules/MBCI/MBCI.h>
diff --git a/dev/kernel/HALKit/AMD64/PCI/DMA.cc b/dev/kernel/HALKit/AMD64/PCI/DMA.cc
new file mode 100644
index 00000000..c756a572
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/DMA.cc
@@ -0,0 +1,87 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <KernelKit/PCI/DMA.h>
+
+namespace NeOS
+{
+ 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..\n";
+ return reinterpret_cast<UIntPtr>(this->fAddress) >= offset;
+ }
+
+ bool DMAWrapper::Write(const UIntPtr& bit, const UInt32& offset)
+ {
+ kout << "[DMAWrapper::Read] Checking this->fAddress..\n";
+
+ if (!this->fAddress)
+ return false;
+
+ kout << "[DMAWrapper::Write] Writing at address..\n";
+
+ auto addr =
+ (volatile UIntPtr*)(reinterpret_cast<UIntPtr>(this->fAddress) + offset);
+ *addr = bit;
+
+ return true;
+ }
+
+ UIntPtr DMAWrapper::Read(const UInt32& offset)
+ {
+ kout << "[DMAWrapper::Read] Checking this->fAddress..\n";
+
+ if (!this->fAddress)
+ return 0;
+
+ kout << "[DMAWrapper::Read] Reading this->fAddress..\n";
+
+ return *(volatile UIntPtr*)(reinterpret_cast<UIntPtr>(this->fAddress) + offset);
+ ;
+ }
+
+ UIntPtr DMAWrapper::operator[](const UIntPtr& offset)
+ {
+ return this->Read(offset);
+ }
+
+ OwnPtr<IOBuf<Char*>> DMAFactory::Construct(OwnPtr<DMAWrapper>& dma)
+ {
+ if (!dma)
+ return {};
+
+ OwnPtr<IOBuf<Char*>> dmaOwnPtr =
+ make_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 NeOS
diff --git a/dev/kernel/HALKit/AMD64/PCI/Database.cc b/dev/kernel/HALKit/AMD64/PCI/Database.cc
new file mode 100644
index 00000000..c5aa1282
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/Database.cc
@@ -0,0 +1,11 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <KernelKit/PCI/Database.h>
+
+namespace NeOS
+{
+}
diff --git a/dev/kernel/HALKit/AMD64/PCI/Device.cc b/dev/kernel/HALKit/AMD64/PCI/Device.cc
new file mode 100644
index 00000000..348e058a
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/Device.cc
@@ -0,0 +1,171 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#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
+
+NeOS::UInt NE_PCIReadRaw(NeOS::UInt bar, NeOS::UShort bus, NeOS::UShort dev, NeOS::UShort fun)
+{
+ NeOS::UInt target = 0x80000000 | ((NeOS::UInt)bus << 16) |
+ ((NeOS::UInt)dev << 11) | ((NeOS::UInt)fun << 8) |
+ (bar & 0xFC);
+
+ NeOS::HAL::rt_out32((NeOS::UShort)NeOS::PCI::PciConfigKind::ConfigAddress,
+ target);
+
+ NeOS::HAL::rt_wait_400ns();
+
+ return NeOS::HAL::rt_in32((NeOS::UShort)NeOS::PCI::PciConfigKind::ConfigData);
+}
+
+void NE_PCISetCfgTarget(NeOS::UInt bar, NeOS::UShort bus, NeOS::UShort dev, NeOS::UShort fun)
+{
+ NeOS::UInt target = 0x80000000 | ((NeOS::UInt)bus << 16) |
+ ((NeOS::UInt)dev << 11) | ((NeOS::UInt)fun << 8) |
+ (bar & 0xFC);
+
+ NeOS::HAL::rt_out32((NeOS::UShort)NeOS::PCI::PciConfigKind::ConfigAddress,
+ target);
+
+ NeOS::HAL::rt_wait_400ns();
+}
+
+namespace NeOS::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::ConfigData, (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::ConfigData, 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::ConfigData, 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(0x0, 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 bar_in)
+ {
+ UInt32 enable = Read(bar_in, sizeof(UInt32));
+ enable |= (1 << 1);
+
+ Write(bar_in, enable, sizeof(UInt32));
+ }
+
+ void Device::BecomeBusMaster(UInt32 bar_in)
+ {
+ UInt32 enable = Read(bar_in, sizeof(UInt32));
+ enable |= (1 << 2);
+
+ Write(bar_in, enable, sizeof(UInt32));
+ }
+
+ UIntPtr Device::Bar(UInt32 bar_in)
+ {
+ UInt32 bar = NE_PCIReadRaw(bar_in & ~0x03, 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 = VendorId();
+
+ if (vendor != (UShort)PciConfigKind::Invalid)
+ fDevice = (UShort)Read(0x0, sizeof(UShort));
+
+ return fDevice;
+ }
+
+ Device::operator bool()
+ {
+ return VendorId() != (UShort)PciConfigKind::Invalid;
+ }
+} // namespace NeOS::PCI
diff --git a/dev/kernel/HALKit/AMD64/PCI/Express.cc b/dev/kernel/HALKit/AMD64/PCI/Express.cc
new file mode 100644
index 00000000..487cbd39
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/Express.cc
@@ -0,0 +1,11 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <KernelKit/PCI/Express.h>
+
+namespace NeOS
+{
+}
diff --git a/dev/kernel/HALKit/AMD64/PCI/IO.cc b/dev/kernel/HALKit/AMD64/PCI/IO.cc
new file mode 100644
index 00000000..c20e1b0e
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/IO.cc
@@ -0,0 +1,7 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <KernelKit/PCI/IO.h>
diff --git a/dev/kernel/HALKit/AMD64/PCI/Iterator.cc b/dev/kernel/HALKit/AMD64/PCI/Iterator.cc
new file mode 100644
index 00000000..bf215fe2
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/Iterator.cc
@@ -0,0 +1,39 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <KernelKit/PCI/Iterator.h>
+
+namespace NeOS::PCI
+{
+ Iterator::Iterator(const Types::PciDeviceKind& type)
+ {
+ // probe devices.
+ for (int bus = 0; bus < NE_BUS_COUNT; ++bus)
+ {
+ for (int device = 0; device < NE_DEVICE_COUNT; ++device)
+ {
+ for (int function = 0; function < NE_FUNCTION_COUNT; ++function)
+ {
+ Device dev(bus, device, function, 0x00);
+
+ if (dev.Class() == type)
+ {
+ fDevices[bus] = dev;
+ }
+ }
+ }
+ }
+ }
+
+ Iterator::~Iterator()
+ {
+ }
+
+ Ref<PCI::Device> Iterator::operator[](const Size& at)
+ {
+ return fDevices[at];
+ }
+} // namespace NeOS::PCI
diff --git a/dev/kernel/HALKit/AMD64/PCI/PCI.cc b/dev/kernel/HALKit/AMD64/PCI/PCI.cc
new file mode 100644
index 00000000..01f2c23b
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/PCI/PCI.cc
@@ -0,0 +1,7 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <KernelKit/PCI/PCI.h>
diff --git a/dev/kernel/HALKit/AMD64/Paging.h b/dev/kernel/HALKit/AMD64/Paging.h
new file mode 100644
index 00000000..4e2ac1b1
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/Paging.h
@@ -0,0 +1,99 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#pragma once
+
+/** ---------------------------------------------------
+
+ * THIS FILE CONTAINS CODE FOR X86_64 PAGING.
+
+------------------------------------------------------- */
+
+#include <NewKit/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(NeOS::VoidPtr addr);
+EXTERN_C void hal_write_cr3(NeOS::VoidPtr cr3);
+EXTERN_C void hal_write_cr0(NeOS::VoidPtr bit);
+
+EXTERN_C NeOS::VoidPtr hal_read_cr0(); // @brief CPU control register.
+EXTERN_C NeOS::VoidPtr hal_read_cr2(); // @brief Fault address.
+EXTERN_C NeOS::VoidPtr hal_read_cr3(); // @brief Page table.
+
+namespace NeOS::HAL
+{
+ /// @brief Final page entry (Not PML, PDPT)
+ struct PACKED NE_PTE final
+ {
+ UInt64 Present : 1;
+ UInt64 Wr : 1;
+ UInt64 User : 1;
+ UInt64 Wt : 1;
+ UInt64 Cache : 1;
+ UInt64 Accessed : 1;
+ UInt64 Dirty : 1;
+ UInt64 MemoryType : 1;
+ UInt64 Global : 1;
+ UInt64 Resvered1 : 3;
+ UInt64 PhysicalAddress : 36;
+ UInt64 Reserved2 : 10;
+ UInt64 ProtectionKey : 5;
+ UInt64 ExecDisable : 1;
+ };
+
+ namespace Detail
+ {
+ enum class ControlRegisterBits
+ {
+ ProtectedModeEnable = 0,
+ MonitorCoProcessor = 1,
+ Emulation = 2,
+ TaskSwitched = 3,
+ ExtensionType = 4,
+ NumericError = 5,
+ WriteProtect = 16,
+ AlignementMask = 18,
+ NotWriteThrough = 29,
+ CacheDisable = 30,
+ PageEnable = 31,
+ };
+
+ inline UInt8 control_register_cast(ControlRegisterBits reg)
+ {
+ return static_cast<UInt8>(reg);
+ }
+ } // namespace Detail
+
+ struct NE_PDE final
+ {
+ NE_PTE* ALIGN(kPageAlign) fEntries[kPageMax];
+ };
+
+ auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page) -> VoidPtr;
+ auto mm_free_bitmap(VoidPtr page_ptr) -> Bool;
+} // namespace NeOS::HAL
+
+namespace NeOS
+{
+ typedef HAL::NE_PTE PTE;
+ typedef HAL::NE_PDE PDE;
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/AMD64/Processor.h b/dev/kernel/HALKit/AMD64/Processor.h
new file mode 100644
index 00000000..d223c320
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/Processor.h
@@ -0,0 +1,326 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+ File: Prcoessor.h
+ Purpose: AMD64 processor abstraction.
+
+ Revision History:
+
+ 30/01/24: Added file (amlel)
+
+------------------------------------------- */
+
+#pragma once
+
+#include <NewKit/Array.h>
+#include <NewKit/Defines.h>
+#include <NewKit/Utils.h>
+#include <FirmwareKit/Handover.h>
+#include <HALKit/AMD64/Paging.h>
+
+#define kPITControlPort (0x43)
+#define kPITChannel0Port (0x40)
+#define kPITFrequency (1193180)
+
+#define kPICCommand (0x20)
+#define kPICData (0x21)
+#define kPIC2Command (0xA0)
+#define kPIC2Data (0xA1)
+
+EXTERN_C
+{
+#include <cpuid.h>
+}
+
+#include <HALKit/AMD64/CPUID.h>
+
+/// @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 kTrapGate (0xEF)
+#define kTaskGate (0b10001100)
+#define kIDTSelector (0x08)
+
+namespace NeOS
+{
+ 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 NeOS
+
+namespace NeOS::HAL
+{
+ /// @brief Memory Manager mapping flags.
+ enum
+ {
+ kMMFlagsInvalid = 0 << 0,
+ kMMFlagsPresent = 1 << 0,
+ kMMFlagsWr = 1 << 1,
+ kMMFlagsUser = 1 << 2,
+ kMMFlagsNX = 1 << 3,
+ kMMFlagsCount = 4,
+ };
+
+ struct PACKED Register64 final
+ {
+ UShort Limit;
+ UIntPtr Base;
+ };
+
+ struct PACKED RegisterGDT 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 final
+ {
+ RawRegister R8{0};
+ RawRegister R9{0};
+ RawRegister R10{0};
+ RawRegister FS{0};
+ RawRegister R12{0};
+ RawRegister R13{0};
+ RawRegister R14{0};
+ RawRegister R15{0};
+ RawRegister GS{0};
+ RawRegister SP{0};
+ RawRegister BP{0};
+ };
+
+ 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(RegisterGDT& gdt);
+ static Void Load(Ref<RegisterGDT>& 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_get_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.
+ /***********************************************************************************/
+ 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);
+ }
+
+ UIntPtr hal_get_phys_address(VoidPtr virtual_address);
+
+ /***********************************************************************************/
+ /// @brief Get Model specific register inside core.
+ /// @param msr MSR
+ /// @param lo low byte
+ /// @param hi high byte
+ /***********************************************************************************/
+ inline UInt32 hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) noexcept
+ {
+ if (!lo || !hi)
+ return 0;
+
+ asm volatile("rdmsr"
+ : "=a"(*lo), "=d"(*hi)
+ : "c"(msr));
+
+ return *lo + *hi;
+ }
+
+ /// @brief Set Model-specific register.
+ /// @param msr MSR
+ /// @param lo low byte
+ /// @param hi high byte
+ inline Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) noexcept
+ {
+ asm volatile("wrmsr"
+ :
+ : "a"(lo), "d"(hi), "c"(msr));
+ }
+
+ /// @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 APICController final
+ {
+ public:
+ explicit APICController(VoidPtr base);
+ ~APICController() = default;
+
+ NE_COPY_DEFAULT(APICController);
+
+ public:
+ UInt32 Read(UInt32 reg) noexcept;
+ Void Write(UInt32 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);
+
+ 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();
+} // namespace NeOS::HAL
+
+EXTERN_C NeOS::Void idt_handle_generic(NeOS::UIntPtr rsp);
+EXTERN_C NeOS::Void idt_handle_gpf(NeOS::UIntPtr rsp);
+EXTERN_C NeOS::Void idt_handle_math(NeOS::UIntPtr rsp);
+EXTERN_C NeOS::Void idt_handle_pf(NeOS::UIntPtr rsp);
+
+EXTERN_C ATTRIBUTE(naked) NeOS::Void hal_load_idt(NeOS::HAL::Register64 ptr);
+EXTERN_C ATTRIBUTE(naked) NeOS::Void hal_load_gdt(NeOS::HAL::RegisterGDT ptr);
+
+inline NeOS::VoidPtr kKernelBitMpStart = nullptr;
+inline NeOS::UIntPtr kKernelBitMpSize = 0UL;
diff --git a/dev/kernel/HALKit/AMD64/ReadMe.md b/dev/kernel/HALKit/AMD64/ReadMe.md
new file mode 100644
index 00000000..02c8c86f
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/ReadMe.md
@@ -0,0 +1,8 @@
+# AMD64 Hardware Abstraction Layer
+
+## Brief
+
+- Supported CPU: AMD64 BASED CPUs.
+- Supported Firmware: EDK 2.
+
+###### Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. All rights reserved.
diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc
new file mode 100644
index 00000000..002266de
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc
@@ -0,0 +1,424 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss Corporation, all rights reserved.
+
+------------------------------------------- */
+
+/**
+ * @file AHCI.cc
+ * @author Amlal El Mahrouss (amlalelmahrouss@icloud.com)
+ * @brief AHCI driver.
+ * @version 0.1
+ * @date 2024-02-02
+ *
+ * @copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved.
+ *
+ */
+
+#include <KernelKit/DeviceMgr.h>
+#include <KernelKit/DriveMgr.h>
+#include <KernelKit/UserProcessScheduler.h>
+#include <KernelKit/LPC.h>
+
+#include <FirmwareKit/EPM.h>
+
+#include <modules/ATA/ATA.h>
+#include <modules/AHCI/AHCI.h>
+#include <KernelKit/PCI/Iterator.h>
+#include <NewKit/Utils.h>
+#include <KernelKit/LockDelegate.h>
+
+#include <StorageKit/AHCI.h>
+
+#define kHBAErrTaskFile (1 << 30)
+#define kHBAPxCmdST (0x0001)
+#define kHBAPxCmdFre (0x0010)
+#define kHBAPxCmdFR (0x4000)
+#define kHBAPxCmdCR (0x8000)
+
+#define kSATALBAMode (1 << 6)
+
+#define kSATASRBsy (0x80)
+#define kSATASRDrq (0x08)
+
+#define kHBABohcBiosOwned (1 << 0)
+#define kHBABohcOSOwned (1 << 1)
+
+#define kSATAPortCnt (0x20)
+
+#define kSATASig (0x00000101)
+#define kSATAPISig (0xEB140101)
+
+#define kSATAProgIfAHCI (0x01)
+#define kSATASubClass (0x06)
+#define kSATABar5 (0x24)
+
+using namespace NeOS;
+
+STATIC PCI::Device kSATADev;
+STATIC HbaMem* kSATAHba;
+STATIC Lba kSATASectorCount = 0UL;
+STATIC UInt16 kSATAIndex = 0U;
+STATIC Char kCurrentDiskModel[50] = {"UNKNOWN AHCI DRIVE"};
+STATIC UInt16 kSATAPortsImplemented = 0U;
+
+template <BOOL Write, BOOL CommandOrCTRL, BOOL Identify>
+STATIC Void drv_std_input_output(UInt64 lba, UInt8* buffer, SizeT sector_sz, SizeT size_buffer) noexcept;
+
+STATIC Int32 drv_find_cmd_slot(HbaPort* port) noexcept;
+
+STATIC Void drv_compute_disk_ahci() noexcept;
+
+STATIC Void drv_compute_disk_ahci() noexcept
+{
+ kSATASectorCount = 0UL;
+
+ const UInt16 kSzIdent = kib_cast(1);
+
+ UInt8 identify_data[kSzIdent] = {0};
+
+ rt_set_memory(identify_data, 0, kSzIdent);
+
+ drv_std_input_output<NO, YES, YES>(0, identify_data, kAHCISectorSize, kSzIdent);
+
+ kSATASectorCount = (identify_data[61] << 16) | identify_data[60];
+
+ kout << "Disk Model: " << kCurrentDiskModel << kendl;
+ kout << "Disk Size: " << number(drv_get_size()) << kendl;
+ kout << "Disk Sector Count: " << number(kSATASectorCount) << kendl;
+}
+
+STATIC Int32 drv_find_cmd_slot(HbaPort* port) noexcept
+{
+ UInt32 slots = (port->Sact | port->Ci);
+
+ for (Int32 i = 0; i < kSATAPortCnt; ++i)
+ {
+ if ((slots & 1) == 0)
+ return i;
+
+ slots >>= 1;
+ }
+
+ return ~0;
+}
+
+template <BOOL Write, BOOL CommandOrCTRL, BOOL Identify>
+STATIC Void drv_std_input_output(UInt64 lba, UInt8* buffer, SizeT sector_sz, SizeT size_buffer) noexcept
+{
+ UIntPtr slot = 0UL;
+
+ slot = drv_find_cmd_slot(&kSATAHba->Ports[kSATAIndex]);
+
+ if (slot == ~0)
+ return;
+
+ volatile HbaCmdHeader* command_header = ((HbaCmdHeader*)(((UInt64)kSATAHba->Ports[kSATAIndex].Clb)));
+
+ command_header += slot;
+
+ MUST_PASS(command_header);
+
+ command_header->Cfl = sizeof(FisRegH2D) / sizeof(UInt32);
+ command_header->Write = Write;
+ command_header->Prdtl = (UInt16)((size_buffer - 1) >> 4) + 1;
+
+ HbaCmdTbl* command_table = (HbaCmdTbl*)((VoidPtr)((UInt64)command_header->Ctba));
+
+ rt_set_memory(command_table, 0, sizeof(HbaCmdTbl) + (command_header->Prdtl - 1) * sizeof(HbaPrdtEntry));
+
+ MUST_PASS(command_table);
+
+ UIntPtr buffer_phys = HAL::hal_get_phys_address(buffer);
+
+ UInt16 prd_i = 0;
+
+ for (; prd_i < (command_header->Prdtl - 1); prd_i++)
+ {
+ command_table->Prdt[prd_i].Dbc = ((size_buffer / command_header->Prdtl - 1) - 1);
+ command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys + (prd_i * command_table->Prdt[prd_i].Dbc));
+ command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32) + (prd_i * command_table->Prdt[prd_i].Dbc));
+ command_table->Prdt[prd_i].Ie = YES;
+ }
+
+ command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys + (prd_i * command_table->Prdt[prd_i].Dbc));
+ command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32) + (prd_i * command_table->Prdt[prd_i].Dbc));
+ command_table->Prdt[prd_i].Dbc = ((size_buffer / command_header->Prdtl - 1) - 1);
+ command_table->Prdt[prd_i].Ie = YES;
+
+ FisRegH2D* h2d_fis = (FisRegH2D*)(&command_table->Cfis);
+
+ h2d_fis->FisType = kFISTypeRegH2D;
+ h2d_fis->CmdOrCtrl = CommandOrCTRL;
+ h2d_fis->Command = Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx;
+
+ if (Identify)
+ h2d_fis->Command = kAHCICmdIdentify;
+
+ h2d_fis->Lba0 = (lba)&0xFF;
+ h2d_fis->Lba1 = (lba >> 8) & 0xFF;
+ h2d_fis->Lba2 = (lba >> 16) & 0xFF;
+
+ h2d_fis->Device = Identify ? 0U : kSATALBAMode;
+
+ h2d_fis->Lba3 = (lba >> 24) & 0xFF;
+ h2d_fis->Lba4 = (lba >> 32) & 0xFF;
+ h2d_fis->Lba5 = (lba >> 40) & 0xFF;
+
+ h2d_fis->CountLow = (size_buffer)&0xFF;
+ h2d_fis->CountHigh = (size_buffer >> 8) & 0xFF;
+
+ while (kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq))
+ {
+ ;
+ }
+
+ kSATAHba->Ports[kSATAIndex].Ci = (1 << slot);
+
+ while (YES)
+ {
+ if (!(kSATAHba->Ports[kSATAIndex].Ci & (1 << slot)))
+ break;
+
+ if (kSATAHba->Is & kHBAErrTaskFile)
+ {
+ err_global_get() = kErrorDiskIsCorrupted;
+ return;
+ }
+ }
+
+ if (kSATAHba->Is & kHBAErrTaskFile)
+ {
+ err_global_get() = kErrorDiskIsCorrupted;
+ return;
+ }
+}
+
+/***
+ @brief Gets the number of sectors inside the drive.
+ @return Sector size in bytes.
+ */
+SizeT drv_get_sector_count_ahci()
+{
+ return kSATASectorCount;
+}
+
+/// @brief Get the drive size.
+/// @return Disk size in bytes.
+SizeT drv_get_size_ahci()
+{
+ return drv_get_sector_count() * kAHCISectorSize;
+}
+
+/// @brief Enable Host and probe using the IDENTIFY command.
+STATIC Void ahci_enable_and_probe()
+{
+ if (kSATAHba->Bohc & kHBABohcBiosOwned)
+ {
+ kSATAHba->Bohc |= kHBABohcOSOwned;
+
+ while (kSATAHba->Bohc & kHBABohcBiosOwned)
+ {
+ ;
+ }
+ }
+
+ // Poll until ready.
+ while (kSATAHba->Ports[kSATAIndex].Cmd & kHBAPxCmdCR)
+ {
+ ;
+ }
+
+ kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdFre;
+ kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdST;
+
+ drv_compute_disk_ahci();
+}
+
+/// @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)
+{
+ PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController);
+
+ 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)
+ {
+ HbaMem* mem_ahci = (HbaMem*)kSATADev.Bar(kSATABar5);
+
+ kSATADev.EnableMmio((UIntPtr)mem_ahci);
+ kSATADev.BecomeBusMaster((UIntPtr)mem_ahci);
+
+ UInt32 ports_implemented = mem_ahci->Pi;
+ UInt16 ahci_index = 0;
+
+ pi = ports_implemented;
+
+ const UInt16 kMaxPortsImplemented = kSATAPortCnt;
+ const UInt32 kSATASignature = kSATASig;
+ const UInt32 kSATAPISignature = kSATAPISig;
+ const UInt8 kSATAPresent = 0x03;
+ const UInt8 kSATAIPMActive = 0x01;
+
+ kSATAHba = mem_ahci;
+
+ 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)
+ {
+ kout << "Detect: /dev/sat" << number(ahci_index) << kendl;
+
+ kSATAIndex = ahci_index;
+ kSATAHba = mem_ahci;
+
+ ahci_enable_and_probe();
+
+ break;
+ }
+ else if (atapi && kSATAPISignature == mem_ahci->Ports[ahci_index].Sig)
+ {
+ kout << "Detect: /dev/atp" << number(ahci_index) << kendl;
+
+ kSATAIndex = ahci_index;
+ kSATAHba = mem_ahci;
+
+ ahci_enable_and_probe();
+
+ break;
+ }
+
+ ports_implemented >>= 1;
+ ++ahci_index;
+ }
+
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+Bool drv_std_detected_ahci()
+{
+ return kSATADev.DeviceId() != (UShort)PCI::PciConfigKind::Invalid && kSATADev.Bar(kSATABar5) != 0;
+}
+
+namespace NeOS
+{
+ UInt16 sk_init_ahci_device(BOOL atapi)
+ {
+ UInt16 pi = 0;
+ return drv_std_init_ahci(pi, atapi);
+
+ kSATAPortsImplemented = pi;
+
+ return pi;
+ }
+
+ namespace Detail
+ {
+ /// @brief Read AHCI device.
+ /// @param self device
+ /// @param mnt mounted disk.
+ STATIC Void sk_io_read_ahci(IDeviceObject<MountpointInterface*>* self, MountpointInterface* mnt)
+ {
+ AHCIDeviceInterface* dev = (AHCIDeviceInterface*)self;
+
+ if (!dev)
+ return;
+
+ auto disk = mnt->GetAddressOf(dev->GetIndex());
+
+ if (!disk)
+ return;
+
+ drv_std_input_output<NO, YES, NO>(disk->fPacket.fPacketLba, (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(IDeviceObject<MountpointInterface*>* self, MountpointInterface* mnt)
+ {
+ AHCIDeviceInterface* dev = (AHCIDeviceInterface*)self;
+
+ if (!dev)
+ return;
+
+ auto disk = mnt->GetAddressOf(dev->GetIndex());
+
+ if (!disk)
+ return;
+
+ drv_std_input_output<YES, YES, NO>(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize);
+ }
+ } // namespace Detail
+
+ ErrorOr<AHCIDeviceInterface> sk_acquire_ahci_device(Int32 drv_index)
+ {
+ if (!drv_std_detected_ahci())
+ return ErrorOr<AHCIDeviceInterface>(kErrorDisk);
+
+ AHCIDeviceInterface device(Detail::sk_io_read_ahci,
+ Detail::sk_io_write_ahci,
+ nullptr);
+
+ device.SetPortsImplemented(kSATAPortsImplemented);
+ device.SetIndex(drv_index);
+
+ return ErrorOr<AHCIDeviceInterface>(device);
+ }
+} // namespace NeOS
+
+#ifdef __AHCI__
+
+Void drv_std_write(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer)
+{
+ drv_std_input_output<YES, YES, NO>(lba, (UInt8*)buffer, sector_sz, size_buffer);
+}
+
+Void drv_std_read(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer)
+{
+ drv_std_input_output<NO, YES, NO>(lba, (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_get_sector_count()
+{
+ return drv_get_sector_count_ahci();
+}
+
+/// @brief Get the drive size.
+/// @return Disk size in bytes.
+SizeT drv_get_size()
+{
+ return drv_get_size_ahci();
+}
+
+#endif // ifdef __AHCI__
diff --git a/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc
new file mode 100644
index 00000000..e025d24d
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc
@@ -0,0 +1,253 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+/**
+ * @file ATA-PIO.cc
+ * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com)
+ * @brief ATA driver (PIO mode).
+ * @version 0.1
+ * @date 2024-02-02
+ *
+ * @copyright Copyright (c) Amlal EL Mahrouss
+ *
+ */
+
+#include <modules/ATA/ATA.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/PCI/Iterator.h>
+
+#if defined(__ATA_DMA__)
+
+#define kATADataLen (256)
+
+using namespace NeOS;
+using namespace NeOS::HAL;
+
+/// BUGS: 0
+
+STATIC Boolean kATADetected = false;
+STATIC Int32 kATADeviceType = kATADeviceCount;
+STATIC Char kATAData[kATADataLen] = {0};
+STATIC NeOS::PCI::Device kATADevice;
+STATIC Char kCurrentDiskModel[50] = {"UNKNOWN DMA DRIVE"};
+
+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)
+{
+ 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.
+
+ // if SATA and then interface is AHCI...
+ if (kATADevice.Subclass() == 0x01)
+ {
+ UInt16 IO = Bus;
+
+ drv_std_select(IO);
+
+ // Bus init, NEIN bit.
+ rt_out8(IO + ATA_REG_NEIN, 1);
+
+ // identify until it's good.
+ ATAInit_Retry:
+ auto status_rdy = rt_in8(IO + ATA_REG_STATUS);
+
+ if (status_rdy & ATA_SR_ERR)
+ {
+ return false;
+ }
+
+ if ((status_rdy & ATA_SR_BSY))
+ goto ATAInit_Retry;
+
+ rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
+
+ /// fetch serial info
+ /// model, speed, number of sectors...
+
+ drv_std_wait_io(IO);
+
+ for (SizeT i = 0ul; i < kATADataLen; ++i)
+ {
+ drv_std_wait_io(IO);
+ kATAData[i] = NeOS::HAL::rt_in16(IO + ATA_REG_DATA);
+ drv_std_wait_io(IO);
+ }
+
+ for (SizeT i = 0; i < 40; i += 2)
+ {
+ kCurrentDiskModel[i * 2] = kATAData[27 + i * 2] >> 8;
+ kCurrentDiskModel[i * 2 + 1] = kATAData[27 + i * 2] & 0xFF;
+ }
+
+ kCurrentDiskModel[40] = '\0';
+
+ kout << "Drive Model: " << kCurrentDiskModel << kendl;
+
+ OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO;
+ OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE;
+
+ return YES;
+ }
+ }
+
+ ke_panic(RUNTIME_CHECK_BOOTSTRAP, "Invalid ATA DMA driver, not detected");
+
+ return NO;
+}
+
+namespace Detail
+{
+ using namespace NeOS;
+
+ struct PRDEntry
+ {
+ UInt32 mAddress;
+ UInt16 mByteCount;
+ UInt16 mFlags;
+ };
+} // namespace Detail
+
+static UIntPtr kReadAddr = mib_cast(2);
+static UIntPtr kWriteAddr = mib_cast(4);
+
+Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size)
+{
+ Lba /= SectorSz;
+
+ if (Size > kib_cast(64))
+ ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers.");
+
+ 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);
+
+ Detail::PRDEntry* prd = (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))
+ ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers.");
+
+ 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);
+
+ Detail::PRDEntry* prd = (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 Getter, gets the number of sectors inside the drive.
+*/
+NeOS::SizeT drv_get_sector_count()
+{
+ return (kATAData[61] << 16) | kATAData[60];
+}
+
+/// @brief Get the drive size.
+NeOS::SizeT drv_get_size()
+{
+ return (drv_get_sector_count()) * kATASectorSize;
+}
+
+#endif /* ifdef __ATA_DMA__ */
diff --git a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc
new file mode 100644
index 00000000..cb629478
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc
@@ -0,0 +1,191 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+/**
+ * @file PIO.cc
+ * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com)
+ * @brief ATA driver (PIO mode).
+ * @version 0.1
+ * @date 2024-02-02
+ *
+ * @copyright Copyright (c) Amlal EL Mahrouss
+ *
+ */
+
+#include <modules/ATA/ATA.h>
+#include <ArchKit/ArchKit.h>
+
+#ifdef __ATA_PIO__
+
+using namespace NeOS;
+using namespace NeOS::HAL;
+
+/// BUGS: 0
+
+#define kATADataLen 512
+
+STATIC Boolean kATADetected = false;
+STATIC Int32 kATADeviceType = kATADeviceCount;
+STATIC Char kATAData[kATADataLen] = {0};
+STATIC Char kCurrentDiskModel[50] = {"UNKNOWN PIO DRIVE"};
+
+Boolean drv_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;
+}
+
+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)
+{
+ UInt16 IO = Bus;
+
+ drv_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;
+
+ rt_out8(OutBus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
+
+ drv_std_wait_io(IO);
+
+ /// fetch serial info
+ /// model, speed, number of sectors...
+
+ for (SizeT i = 0ul; i < kATADataLen; ++i)
+ {
+ kATAData[i] = HAL::rt_in16(OutBus + ATA_REG_DATA);
+ }
+
+ for (Int32 i = 0; i < 20; i++)
+ {
+ kCurrentDiskModel[i * 2] = kATAData[27 + i] >> 8;
+ kCurrentDiskModel[i * 2 + 1] = kATAData[27 + i + 1] & 0xFF;
+ }
+
+ kCurrentDiskModel[40] = '\0';
+
+ kout << "Detect: /dev/ata0" << kendl;
+
+ kout << "Drive Model: " << kCurrentDiskModel << kendl;
+
+ return true;
+}
+
+Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size)
+{
+ Lba /= SectorSz;
+
+ UInt8 Command = ((!Master) ? 0xE0 : 0xF0);
+
+ drv_std_wait_io(IO);
+ drv_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);
+
+ for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff)
+ {
+ drv_std_wait_io(IO);
+ Buf[IndexOff] = HAL::rt_in16(IO + ATA_REG_DATA);
+ }
+}
+
+Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size)
+{
+ Lba /= SectorSz;
+
+ UInt8 Command = ((!Master) ? 0xE0 : 0xF0);
+
+ drv_std_wait_io(IO);
+ drv_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);
+
+ for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff)
+ {
+ drv_std_wait_io(IO);
+ rt_out16(IO + ATA_REG_DATA, Buf[IndexOff]);
+ }
+}
+
+/// @brief is ATA detected?
+Boolean drv_std_detected(Void)
+{
+ return kATADetected;
+}
+
+/***
+ @brief Getter, gets the number of sectors inside the drive.
+ */
+SizeT drv_get_sector_count()
+{
+ return (kATAData[61] << 16) | kATAData[60];
+}
+
+/// @brief Get the drive size.
+SizeT drv_get_size()
+{
+ return (drv_get_sector_count()) * kATASectorSize;
+}
+
+#endif /* ifdef __ATA_PIO__ */ \ No newline at end of file
diff --git a/dev/kernel/HALKit/AMD64/make_ap_blob.sh b/dev/kernel/HALKit/AMD64/make_ap_blob.sh
new file mode 100755
index 00000000..3f079187
--- /dev/null
+++ b/dev/kernel/HALKit/AMD64/make_ap_blob.sh
@@ -0,0 +1,3 @@
+# !/bin/sh
+
+nasm -f bin HalApplicationProcessorStartup.asm -o HalApplicationProcessorStartup.bin \ No newline at end of file