diff options
| author | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2025-03-23 19:13:48 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2025-03-23 19:15:17 +0100 |
| commit | a13e1c0911c0627184bc38f18c7fdda64447b3ad (patch) | |
| tree | 073a62c09bf216e85a3f310376640fa1805147f9 /dev/kernel/HALKit | |
| parent | 149fa096eb306d03686b3b67e813cf1a78e08cd0 (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')
87 files changed, 5479 insertions, 0 deletions
diff --git a/dev/kernel/HALKit/.gitkeep b/dev/kernel/HALKit/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/.gitkeep 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 diff --git a/dev/kernel/HALKit/ARM64/APM/APM+IO.cc b/dev/kernel/HALKit/ARM64/APM/APM+IO.cc new file mode 100644 index 00000000..752f29f9 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/APM/APM+IO.cc @@ -0,0 +1,37 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/APM/APM.h> +#include <KernelKit/LPC.h> + +using namespace NeOS; + +/// @brief Send APM command to it's space. +/// @param base_dma the IO base port. +/// @param cmd the command. +/// @return status code. +EXTERN_C Int32 apm_send_io_command(UInt16 cmd, APMPowerCmd value) +{ + switch (cmd) + { + case kAPMPowerCommandReboot: { + asm volatile( + "ldr x0, =0x84000004\n" + "svc #0\n"); + + return kErrorSuccess; + } + case kAPMPowerCommandShutdown: { + asm volatile( + "ldr x0, =0x84000008\n" + "svc #0\n"); + + return kErrorSuccess; + } + default: + return kErrorInvalidData; + } +} diff --git a/dev/kernel/HALKit/ARM64/ApplicationProcessor.h b/dev/kernel/HALKit/ARM64/ApplicationProcessor.h new file mode 100644 index 00000000..d263f9b8 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/ApplicationProcessor.h @@ -0,0 +1,19 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <HALKit/ARM64/Processor.h> + +/************************************************** */ +/* INITIALIZE THE GIC ON CPU. */ +/************************************************** */ + +namespace NeOS +{ + BOOL mp_initialize_gic(NeOS::Void); +}
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc b/dev/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc new file mode 100644 index 00000000..a25112ae --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NewKit/KString.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> +#include <modules/APM/APM.h> + +namespace NeOS +{ + ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) + : fRsdp(rsp_ptr), fEntries(0) + { + } + + BOOL ACPIFactoryInterface::Shutdown() + { + apm_send_io_command(kAPMPowerCommandShutdown, 0); + return NO; + } + + /// @brief Reboot machine in either ACPI or by triple faulting. + /// @return nothing it's a reboot. + Void ACPIFactoryInterface::Reboot() + { + apm_send_io_command(kAPMPowerCommandReboot, 0); + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc b/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc new file mode 100644 index 00000000..660af502 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc @@ -0,0 +1,145 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/ARM64/Processor.h>
+#include <KernelKit/DebugOutput.h>
+#include <HALKit/ARM64/ApplicationProcessor.h>
+#include <KernelKit/UserProcessScheduler.h>
+
+#define GICD_BASE 0x08000000 // Distributor base address
+#define GICC_BASE 0x08010000 // CPU interface base address
+
+#define GICD_CTLR 0x000 // Distributor Control Register
+#define GICD_ISENABLER 0x100 // Interrupt Set-Enable Registers
+#define GICD_ICENABLER 0x180 // Interrupt Clear-Enable Registers
+#define GICD_ISPENDR 0x200 // Interrupt Set-Pending Registers
+#define GICD_ICPENDR 0x280 // Interrupt Clear-Pending Registers
+#define GICD_IPRIORITYR 0x400 // Interrupt Priority Registers
+#define GICD_ITARGETSR 0x800 // Interrupt Processor Targets Registers
+#define GICD_ICFGR 0xC00 // Interrupt Configuration Registers
+
+#define GICC_CTLR 0x000 // CPU Interface Control Register
+#define GICC_PMR 0x004 // Interrupt Priority Mask Register
+#define GICC_IAR 0x00C // Interrupt Acknowledge Register
+#define GICC_EOIR 0x010 // End of Interrupt Register
+
+// ================================================================= //
+
+namespace NeOS
+{
+ struct PROCESS_CONTROL_BLOCK final
+ {
+ HAL::StackFramePtr mFrame;
+ };
+
+ STATIC PROCESS_CONTROL_BLOCK kProcessBlocks[kSchedProcessLimitPerTeam] = {0};
+
+ namespace Detail
+ {
+ STATIC BOOL kGICEnabled = NO;
+
+ STATIC void mp_hang_fn(void)
+ {
+ while (YES)
+ ;
+
+ dbg_break_point();
+ }
+
+ Void mp_setup_gic_el0(Void)
+ {
+ // enable distributor.
+ ke_dma_write<UInt32>(GICD_BASE, GICD_CTLR, YES);
+
+ UInt32 gicc_ctlr = ke_dma_read<UInt32>(GICC_BASE, GICC_CTLR);
+
+ const auto kEnableSignalInt = YES;
+
+ gicc_ctlr |= kEnableSignalInt; // Enable signaling of interrupts
+ gicc_ctlr |= (kEnableSignalInt << 1); // Allow Group 1 interrupts in EL0
+
+ ke_dma_write<UInt32>(GICC_BASE, GICC_CTLR, gicc_ctlr);
+
+ // Set priority mask (accept all priorities)
+ ke_dma_write<UInt32>(GICC_BASE, GICC_PMR, 0xFF);
+
+ UInt32 icfgr = ke_dma_read<UInt32>(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4);
+
+ icfgr |= (0x2 << ((32 % 16) * 2)); // Edge-triggered
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4, icfgr);
+
+ // Target interrupt 32 to CPU 1
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ITARGETSR + (0x20 / 0x04) * 4, 0x2 << ((32 % 4) * 8));
+
+ // Set interrupt 32 priority to lowest (0xFF)
+ ke_dma_write<UInt32>(GICD_BASE, GICD_IPRIORITYR + (0x20 / 0x04) * 4, 0xFF << ((32 % 4) * 8));
+
+ // Enable interrupt 32 for AP.
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ISENABLER + 4, 0x01);
+ }
+
+ BOOL mp_handle_gic_interrupt_el0(Void)
+ {
+ // Read the interrupt ID
+ UInt32 interrupt_id = ke_dma_read<UInt32>(GICC_BASE, GICC_IAR);
+
+ // Check if it's a valid interrupt (not spurious)
+ if ((interrupt_id & 0x3FF) < 1020)
+ {
+ auto interrupt = interrupt_id & 0x3FF;
+
+ const UInt16 kInterruptScheduler = 0x20;
+
+ kout << "Handling interrupt for AP: " << interrupt << kendl;
+
+ switch (interrupt)
+ {
+ case kInterruptScheduler: {
+ ke_dma_write<UInt32>(GICC_BASE, GICC_EOIR, interrupt_id);
+ UserProcessHelper::StartScheduling();
+ break;
+ }
+ default: {
+ ke_dma_write<UInt32>(GICC_BASE, GICC_EOIR, interrupt_id);
+ break;
+ }
+ }
+
+ return YES;
+ }
+
+ // spurious interrupt
+ return NO;
+ }
+ } // namespace Detail
+
+ EXTERN_C HAL::StackFramePtr mp_get_current_context(ProcessID pid)
+ {
+ return kProcessBlocks[pid % kSchedProcessLimitPerTeam].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;
+
+ return YES;
+ }
+
+ BOOL mp_initialize_gic(Void)
+ {
+ if (!Detail::kGICEnabled)
+ {
+ Detail::kGICEnabled = YES;
+ Detail::mp_setup_gic_el0();
+ }
+
+ return Detail::kGICEnabled;
+ }
+} // namespace NeOS
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/HalDebugOutput.cc b/dev/kernel/HALKit/ARM64/HalDebugOutput.cc new file mode 100644 index 00000000..8d54739f --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalDebugOutput.cc @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + 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> + +namespace NeOS +{ + EXTERN_C void ke_io_write(IDeviceObject<const Char*>* self, const Char* bytes) + { +#ifdef __DEBUG__ + if (*bytes == 0) + return; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = rt_string_len(bytes, 256U); + + volatile UInt8* uart_ptr = (UInt8*)0x09000000; + + while (index < len) + { + if (bytes[index] == '\r') + *uart_ptr = '\r'; + + *uart_ptr = bytes[index] == '\r' ? '\n' : bytes[index]; + ++index; + } +#endif // __DEBUG__ + } + + TerminalDevice::~TerminalDevice() = default; + + EXTERN_C void ke_io_read(IDeviceObject<const Char*>* self, const Char* bytes) + { +#ifdef __DEBUG__ + SizeT index = 0; + + volatile UInt8* uart_ptr = (UInt8*)0x09000000; + + ///! TODO: Look on how to wait for the UART to complete. + while (Yes) + { + auto in = *uart_ptr; + + ///! If enter pressed then break. + if (in == 0xD) + { + break; + } + + if (in < '0' || in < 'A' || in < 'a') + { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || + in != ':') + { + continue; + } + } + + ((char*)bytes)[index] = in; + + ++index; + } + + ((char*)bytes)[index] = 0; +#endif // __DEBUG__ + } + + TerminalDevice TerminalDevice::The() noexcept + { + TerminalDevice out(NeOS::ke_io_write, NeOS::ke_io_read); + return out; + } + +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalFlushTLB.S b/dev/kernel/HALKit/ARM64/HalFlushTLB.S new file mode 100644 index 00000000..8fcf40ff --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalFlushTLB.S @@ -0,0 +1,5 @@ +.text + +hal_flush_tlb: + tlbi + ret diff --git a/dev/kernel/HALKit/ARM64/HalKernelMain.cc b/dev/kernel/HALKit/ARM64/HalKernelMain.cc new file mode 100644 index 00000000..55caca94 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalKernelMain.cc @@ -0,0 +1,54 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <modules/CoreGfx/FBMgr.h> +#include <FirmwareKit/Handover.h> +#include <KernelKit/FileMgr.h> +#include <KernelKit/MemoryMgr.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <NewKit/Json.h> +#include <KernelKit/CodeMgr.h> +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NetworkKit/IPC.h> +#include <HALKit/ARM64/Processor.h> +#include <CFKit/Property.h> + +#include <HALKit/ARM64/ApplicationProcessor.h> + +EXTERN_C void hal_init_platform( + NeOS::HEL::BootInfoHeader* handover_hdr) +{ + + /************************************************** */ + /* INITIALIZE AND VALIDATE HEADER. */ + /************************************************** */ + + kHandoverHeader = handover_hdr; + + if (kHandoverHeader->f_Magic != kHandoverMagic && + kHandoverHeader->f_Version != kHandoverVersion) + { + return; + } + + /************************************** */ + /* INITIALIZE BIT MAP. */ + /************************************** */ + + kKernelBitMpSize = kHandoverHeader->f_BitMapSize; + kKernelBitMpStart = reinterpret_cast<NeOS::VoidPtr>( + reinterpret_cast<NeOS::UIntPtr>(kHandoverHeader->f_BitMapStart)); + + /// @note do initialize the interrupts after it. + + NeOS::mp_initialize_gic(); + + while (YES) + { + } +} diff --git a/dev/kernel/HALKit/ARM64/HalKernelPanic.cc b/dev/kernel/HALKit/ARM64/HalKernelPanic.cc new file mode 100644 index 00000000..5037f440 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalKernelPanic.cc @@ -0,0 +1,80 @@ +/* ------------------------------------------- + + 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; + + Char* message_apicid = new Char[128]; + rt_set_memory(message_apicid, 0, 128); + + rt_copy_memory((VoidPtr) "panic id: ", message_apicid, rt_string_len("panic id: ")); + rt_to_string(message_apicid + rt_string_len("panic id: "), (UIntPtr)id, 10); + + fb_render_string(message_apicid, y, x, panic_text); + + y += 10; + + fb_render_string((message ? message : "message: panic raised, going nowhere after this!"), y, x, panic_text); + + y += 10; + + fb_clear(); + + 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 << "FAILED: FILE: " << file << kendl; + kout << "FAILED: LINE: " << line << kendl; + + ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed + } + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalPagingMgrARM64.cc b/dev/kernel/HALKit/ARM64/HalPagingMgrARM64.cc new file mode 100644 index 00000000..4ec45b51 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalPagingMgrARM64.cc @@ -0,0 +1,86 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: HalPagingMgr.cc + Purpose: Platform Paging Manager. + +------------------------------------------- */ + +#include <HALKit/ARM64/Paging.h> +#include <HALKit/ARM64/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 fVAddr{nullptr}; + } fInternalStore; + + Bool fStoreOp{No}; // Store operation in progress. + + static NE_PAGE_STORE& The() + { + static NE_PAGE_STORE the; + return the; + } + }; + + /// \brief Retrieve the page status of a PTE. + STATIC Void mmi_page_status(PTE* pte) + { + } + + STATIC Int32 mmi_map_page_table_entry(VoidPtr virtual_address, UInt32 flags, PTE* pt_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) + { + if (!virtual_address || + !flags) + return 0; + + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + while (page_store.fStoreOp) + ; + + page_store.fStoreOp = Yes; + + if (page_store.fInternalStore.fVAddr == virtual_address) + { + page_store.fStoreOp = No; + return mmi_map_page_table_entry(page_store.fInternalStore.fVAddr, flags, page_store.fInternalStore.fPte); + } + + return 1; + } + + /// @brief Maps flags for a specific pte. + /// @internal Internal function. + STATIC Int32 mmi_map_page_table_entry(VoidPtr virtual_address, UInt32 flags, PTE* pt_entry) + { + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + // Update internal store. + + page_store.fInternalStore.fPde = nullptr; + page_store.fInternalStore.fPte = pt_entry; + page_store.fInternalStore.fVAddr = virtual_address; + + page_store.fStoreOp = No; + + return 0; + } +} // namespace NeOS::HAL diff --git a/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc b/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc new file mode 100644 index 00000000..55c8aab5 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /// @brief Wakes up thread. + /// Wakes up thread from the hang state. + Void mp_wakeup_thread(HAL::StackFrame* stack) + { + NE_UNUSED(stack); + } + + /// @brief makes the thread sleep on a loop. + /// hooks and hangs thread to prevent code from executing. + Void mp_hang_thread(HAL::StackFrame* stack) + { + NE_UNUSED(stack); + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc b/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc new file mode 100644 index 00000000..3a9b7074 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc @@ -0,0 +1,35 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/ARM64/Processor.h>
+#include <KernelKit/UserProcessScheduler.h>
+
+namespace NeOS
+{
+ /***********************************************************************************/
+ /// @brief Unimplemented function (crashes by default)
+ /// @param void
+ /***********************************************************************************/
+
+ 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;
+ }
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/ARM64/HalTimerARM64.cc b/dev/kernel/HALKit/ARM64/HalTimerARM64.cc new file mode 100644 index 00000000..785d2d5c --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalTimerARM64.cc @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + 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 <ArchKit/ArchKit.h> diff --git a/dev/kernel/HALKit/ARM64/MBCI/MBCI.cc b/dev/kernel/HALKit/ARM64/MBCI/MBCI.cc new file mode 100644 index 00000000..d2df66e6 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/MBCI/MBCI.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/MBCI/MBCI.h>
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/Paging.h b/dev/kernel/HALKit/ARM64/Paging.h new file mode 100644 index 00000000..3c24f757 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Paging.h @@ -0,0 +1,120 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +/** --------------------------------------------------- + + * THIS FILE CONTAINS CODE FOR ARMV8 PAGING. + +------------------------------------------------------- */ + +#include <NewKit/Defines.h> + +#ifndef kPageMax +#define kPageMax (0x200) +#endif //! kPageMax + +#ifndef kPageAlign +#define kPageAlign (0x1000) +#endif //! kPageAlign + +#ifndef kPageSize +#define kPageSize (0x1000) +#endif // !kPageSize + +//! short format address range + +#define c16KBPage 0b000 +#define c8KBPage 0b001 +#define c4KBPage 0b010 +#define c2KBPage 0b011 +#define c1KBPage 0b100 +#define c512BPage 0b101 +#define c256BPage 0b110 +#define c128BPage 0b111 + +/// Long format address range + +#define cPageMAll \ + { \ + 0b000, 0b000 \ + } +#define cPageMToMax(M) \ + { \ + M, 0b000 \ + } +#define cPageMaxToM(M) \ + { \ + 0b000, M \ + } +#define cPageMToN(M, N) \ + { \ + M, N \ + } + +namespace NeOS::HAL +{ + struct PACKED PTE_4KB final + { + UInt64 Valid : 1; + UInt64 Table : 1; + UInt64 AttrIndex : 3; + UInt64 NS : 1; + UInt64 AP : 2; + UInt64 SH : 2; + UInt64 AF : 1; + UInt64 NG : 1; + UInt64 Reserved1 : 1; + UInt64 Contiguous : 1; + UInt64 Dirty : 1; + UInt64 Reserved : 2; + UInt64 PhysicalAddress : 36; + UInt64 Reserved3 : 4; + UInt64 PXN : 1; + UInt64 XN : 1; + UInt64 Reserved4 : 9; + }; + + namespace Detail + { + enum class ControlRegisterBits + { + ProtectedModeEnable = 0, + MonitorCoProcessor = 1, + Emulation = 2, + TaskSwitched = 3, + ExtensionType = 4, + NumericError = 5, + WriteProtect = 16, + AlignementMask = 18, + NotWriteThrough = 29, + CacheDisable = 30, + PageEnable = 31, + }; + + inline UInt8 control_register_cast(ControlRegisterBits reg) + { + return static_cast<UInt8>(reg); + } + } // namespace Detail + + struct PDE_4KB final + { + PTE_4KB ALIGN(kPageAlign) fEntries[kPageMax]; + }; + + auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page) -> VoidPtr; + auto mm_free_bitmap(VoidPtr page_ptr) -> Bool; +} // namespace NeOS::HAL + +namespace NeOS +{ + typedef HAL::PTE_4KB PTE; + typedef HAL::PDE_4KB PDE; +} // namespace NeOS + +EXTERN_C void hal_flush_tlb(); diff --git a/dev/kernel/HALKit/ARM64/Processor.h b/dev/kernel/HALKit/ARM64/Processor.h new file mode 100644 index 00000000..940cfbe9 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Processor.h @@ -0,0 +1,91 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/Handover.h> + +#define kCPUBackendName "ARMv8" + +namespace NeOS::HAL +{ + struct PACKED Register64 final + { + UShort Limit; + UIntPtr Base; + }; + + /// @brief Memory Manager mapping flags. + enum + { + kMMFlagsPresent = 1 << 0, + kMMFlagsWr = 1 << 1, + kMMFlagsUser = 1 << 2, + kMMFlagsNX = 1 << 3, + kMMFlagsCount = 3, + }; + + /// @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); + + typedef UIntPtr Reg; + typedef Register64 Register; + + /// @note let's keep the same name as AMD64 HAL. + struct PACKED StackFrame final + { + Reg R8{0}; + Reg R9{0}; + Reg R10{0}; + Reg R11{0}; + Reg R12{0}; + Reg R13{0}; + Reg R14{0}; + Reg R15{0}; + Reg SP{0}; + Reg BP{0}; + }; + + typedef StackFrame* StackFramePtr; + + inline Void rt_halt() noexcept + { + while (Yes) + { + } + } + + template <typename DataKind> + inline void hal_dma_write(UIntPtr address, DataKind value) + { + *reinterpret_cast<volatile DataKind*>(address) = value; + } + + template <typename DataKind> + inline DataKind hal_dma_read(UIntPtr address) + { + return *reinterpret_cast<volatile DataKind*>(address); + } + + inline Void hal_wfi(Void) + { + asm volatile("wfi"); + } +} // namespace NeOS::HAL + +inline NeOS::VoidPtr kKernelBitMpStart = nullptr; +inline NeOS::UIntPtr kKernelBitMpSize = 0UL; + +inline NeOS::VoidPtr kKernelPhysicalStart = nullptr; + +#include <HALKit/ARM64/Paging.h> diff --git a/dev/kernel/HALKit/ARM64/ReadMe.md b/dev/kernel/HALKit/ARM64/ReadMe.md new file mode 100644 index 00000000..c51229f2 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/ReadMe.md @@ -0,0 +1,3 @@ +# ARM64 Hardware Abstraction Layer + +- Supported Firmware: CoreBoot/EDK/OpenMobileBoot diff --git a/dev/kernel/HALKit/ARM64/Storage/MBCI+Flash+IO+Generic.cc b/dev/kernel/HALKit/ARM64/Storage/MBCI+Flash+IO+Generic.cc new file mode 100644 index 00000000..94d20878 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Storage/MBCI+Flash+IO+Generic.cc @@ -0,0 +1,119 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef NE_USE_MBCI_FLASH + +#include <NewKit/Defines.h> +#include <ArchKit/ArchKit.h> +#include <modules/MFlash/MFlash.h> +#include <modules/MBCI/MBCI.h> + +/// @file MBCI+Flash.cc +/// @brief MBCI Flash support. + +#define MBCI_MAX_SLOTS (8U) + +namespace NeOS +{ + /// /Mount/Flash/n + constexpr auto kFlashBridgeMagic = 0x70768372; + constexpr auto kFlashBridgeRevision = 1; + + STATIC BOOL kFlashEnabled = NO; + STATIC SizeT kFlashSize[MBCI_MAX_SLOTS] = {}; + STATIC SizeT kFlashSectorSz[MBCI_MAX_SLOTS] = {}; + STATIC IMBCIHost* kFlashMetaPackets[MBCI_MAX_SLOTS] = {}; + STATIC IMBCIHost* kFlashDataPackets[MBCI_MAX_SLOTS] = {}; + + STATIC Void drv_std_io(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz); + + /// @brief Enable flash memory builtin. + STATIC Void drv_enable_flash(Int32 slot); + + /// @brief Disable flash memory builtin. + STATIC Void drv_disable_flash(Int32 slot); + + /// @brief get slot sector count. + /// @return slot sector count. + SizeT drv_get_sector_count(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return 0; + + return kFlashSectorSz[slot]; + } + + /// @brief get slot full size (in bytes). + /// @return drive slot size + SizeT drv_get_size(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return 0; + + return kFlashSize[slot]; + } + + /// @brief Enable flash memory at slot. + BOOL drv_enable_at(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return NO; + + kFlashMetaPackets[slot]->InterruptEnable = YES; + + kout << "Enabled hardware slot at: " << number(slot) << kendl; + + return YES; + } + + /// @brief Disable flash memory at slot. + BOOL drv_disable_at(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return NO; + + kFlashMetaPackets[slot]->InterruptEnable = NO; + + kout << "Disabled hardware slot at: " << number(slot) << kendl; + + return YES; + } + + STATIC Void drv_std_io(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz) + { + UInt64* packet_frame = (UInt64*)kFlashDataPackets[slot]->BaseAddressRegister; + + if (packet_frame[0] != (UInt64)kFlashBridgeMagic) + return; + + if (packet_frame[8] != (UInt64)kFlashBridgeRevision) + return; + + packet_frame[16 + 0] = lba; + packet_frame[16 + 4] = sector_sz; + packet_frame[16 + 8] = lba; + packet_frame[16 + 12] = buf_sz; + packet_frame[16 + 14] = (UIntPtr)HAL::hal_get_phys_address(buf); + + while (packet_frame[0] == lba) + ; + } + + Void drv_std_read(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz) + { + rt_set_memory(buf, 0, buf_sz); + + drv_std_io(slot, lba, buf, sector_sz, buf_sz); + } + + Void drv_std_write(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz) + { + drv_std_io(slot, lba, buf, sector_sz, buf_sz); + } + +} // namespace NeOS + +#endif // if NE_USE_MBCI_FLASH diff --git a/dev/kernel/HALKit/ARM64/Storage/UFS+Generic.cc b/dev/kernel/HALKit/ARM64/Storage/UFS+Generic.cc new file mode 100644 index 00000000..20d06671 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Storage/UFS+Generic.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/// @file UFS.cc +/// @brief UFS Flash Memory support. + +#define UFS_PCI_VENDOR_ID (0x01001) /* AKER */ +#define UFS_PCI_DEVICE_ID (0xAEAEA) /* AKER */
\ No newline at end of file diff --git a/dev/kernel/HALKit/AXP/CR.s b/dev/kernel/HALKit/AXP/CR.s new file mode 100644 index 00000000..4d68257d --- /dev/null +++ b/dev/kernel/HALKit/AXP/CR.s @@ -0,0 +1,11 @@ +.globl read_lr1 +.globl read_lr0 + +.section .text + read_lr0: + movq %r30, %cr3 + ret + + hal_read_cr0: + movq %r30, %cr0 + ret
\ No newline at end of file diff --git a/dev/kernel/HALKit/AXP/CoreInterruptHandlerDEC.cpp b/dev/kernel/HALKit/AXP/CoreInterruptHandlerDEC.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/AXP/CoreInterruptHandlerDEC.cpp diff --git a/dev/kernel/HALKit/AXP/CoreSyscallHandlerDEC.cpp b/dev/kernel/HALKit/AXP/CoreSyscallHandlerDEC.cpp new file mode 100644 index 00000000..f77186fd --- /dev/null +++ b/dev/kernel/HALKit/AXP/CoreSyscallHandlerDEC.cpp @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <HALKit/AXP/Processor.h> + +/// @brief Internal call for syscall, to work with C++. +/// @param stack +/// @return nothing. +EXTERN_C void rt_syscall_handle(NeOS::HAL::StackFrame* stack) +{ + if (stack->Rcx <= (kSyscalls.Count() - 1)) + { + kout << "syscall: enter.\r"; + + if (kSyscalls[stack->Rcx].Leak().Leak().fHooked) + (kSyscalls[stack->Rcx].Leak().Leak().fProc)(stack); + + kout << "syscall: exit.\r"; + } +} diff --git a/dev/kernel/HALKit/AXP/HAL.s b/dev/kernel/HALKit/AXP/HAL.s new file mode 100644 index 00000000..0178527f --- /dev/null +++ b/dev/kernel/HALKit/AXP/HAL.s @@ -0,0 +1,13 @@ +.globl rt_wait_400ns + +.section .text +rt_wait_400ns: + jmp .L +.L: + jmp .L2 + wtint ;; wait for interrupt +.L2: + + ret + + diff --git a/dev/kernel/HALKit/AXP/Processor.h b/dev/kernel/HALKit/AXP/Processor.h new file mode 100644 index 00000000..bb14c9c6 --- /dev/null +++ b/dev/kernel/HALKit/AXP/Processor.h @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once diff --git a/dev/kernel/HALKit/AXP/SYSCALL.s b/dev/kernel/HALKit/AXP/SYSCALL.s new file mode 100644 index 00000000..19cab808 --- /dev/null +++ b/dev/kernel/HALKit/AXP/SYSCALL.s @@ -0,0 +1,10 @@ +.section .text +system_handle_user_call: + .cfi_startproc + + push %r0 + jmp %r1 + mov %r30, %r2 + + .cfi_endproc + retsys
\ No newline at end of file diff --git a/dev/kernel/HALKit/AXP/VM.s b/dev/kernel/HALKit/AXP/VM.s new file mode 100644 index 00000000..7024086b --- /dev/null +++ b/dev/kernel/HALKit/AXP/VM.s @@ -0,0 +1,5 @@ +.global hal_flush_tlb + +.section .text +hal_flush_tlb: + swppal
\ No newline at end of file diff --git a/dev/kernel/HALKit/POWER/.gitkeep b/dev/kernel/HALKit/POWER/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/POWER/.gitkeep diff --git a/dev/kernel/HALKit/POWER/AP.h b/dev/kernel/HALKit/POWER/AP.h new file mode 100644 index 00000000..e0ef3ffb --- /dev/null +++ b/dev/kernel/HALKit/POWER/AP.h @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: AP.h + Purpose: POWER hardware threads. + + Revision History: + + 14/04/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + struct HAL_HARDWARE_THREAD; + + /// @brief hardware thread indentification type. + typedef NeOS::Int32 hal_ap_kind; + + /// @brief Hardware thread information structure. + typedef struct HAL_HARDWARE_THREAD + { + NeOS::UIntPtr fStartAddress; + NeOS::UInt8 fPrivleged : 1; + NeOS::UInt32 fPageMemoryFlags; + hal_ap_kind fIdentNumber; + } HAL_HARDWARE_THREAD; + + /// @brief Set PC to specific hart. + /// @param hart the hart + /// @param epc the pc. + /// @return + EXTERN_C NeOS::Void hal_set_pc_to_hart(HAL_HARDWARE_THREAD* hart, NeOS::VoidPtr epc); +} // namespace NeOS diff --git a/dev/kernel/HALKit/POWER/APM/.gitkeep b/dev/kernel/HALKit/POWER/APM/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/POWER/APM/.gitkeep diff --git a/dev/kernel/HALKit/POWER/HalAP.cc b/dev/kernel/HALKit/POWER/HalAP.cc new file mode 100644 index 00000000..32f91a5f --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalAP.cc @@ -0,0 +1,40 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> +#include <HALKit/POWER/AP.h> + +using namespace NeOS; + +namespace NeOS::Detail +{ + STATIC void mp_hang_fn(void) + { + while (YES) + ; + } +} // namespace NeOS::Detail + +/// @brief wakes up thread. +/// wakes up thread from hang. +void mp_wakeup_thread(HAL::StackFramePtr stack) +{ + if (!stack) + return; + + hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(stack->BP)); +} + +/// @brief makes thread sleep. +/// hooks and hangs thread to prevent code from executing. +void mp_hang_thread(HAL::StackFramePtr stack) +{ + if (!stack) + return; + + hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(NeOS::Detail::mp_hang_fn)); +} diff --git a/dev/kernel/HALKit/POWER/HalDebugOutput.cc b/dev/kernel/HALKit/POWER/HalDebugOutput.cc new file mode 100644 index 00000000..e9b2c85a --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalDebugOutput.cc @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> + +using namespace NeOS; + +/// @brief Writes to COM1. +/// @param bytes +void ke_io_write(const Char* bytes) +{ + if (!bytes) + return; + + SizeT index = 0; + SizeT len = rt_string_len(bytes, 256U); + + while (index < len) + { + // TODO + ++index; + } +} diff --git a/dev/kernel/HALKit/POWER/HalStartSequence.s b/dev/kernel/HALKit/POWER/HalStartSequence.s new file mode 100644 index 00000000..2882be80 --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalStartSequence.s @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +.globl __ImageStart +.extern hal_init_platform +.align 4 +.text + +__ImageStart: + bl hal_init_platform + blr diff --git a/dev/kernel/HALKit/POWER/HalThread.cc b/dev/kernel/HALKit/POWER/HalThread.cc new file mode 100644 index 00000000..0d2e140b --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalThread.cc @@ -0,0 +1,8 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> diff --git a/dev/kernel/HALKit/POWER/HalVirtualMemory.cc b/dev/kernel/HALKit/POWER/HalVirtualMemory.cc new file mode 100644 index 00000000..d3d4b694 --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalVirtualMemory.cc @@ -0,0 +1,49 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> +#include <HALKit/POWER/MMU.h> + +/// @note Refer to SoC documentation. + +using namespace NeOS; + +EXTERN_C Void hal_write_tlb(UInt32 mas0, UInt32 mas1, UInt32 mas2, UInt32 mas3, UInt32 mas7) +{ + hal_mtspr(MAS0, mas0); + hal_mtspr(MAS1, mas1); + hal_mtspr(MAS2, mas2); + hal_mtspr(MAS3, mas3); + hal_mtspr(MAS7, mas7); + + hal_flush_tlb(); +} + +EXTERN_C Bool hal_set_tlb(UInt8 tlb, UInt32 epn, UInt64 rpn, UInt8 perms, UInt8 wimge, UInt8 ts, UInt8 esel, UInt8 tsize, UInt8 iprot) +{ + if ((hal_mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 && (tsize & 1)) + { + // this MMU does not allow odd tsize values + return false; + } + + UInt32 mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); + UInt32 mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); + UInt32 mas2 = FSL_BOOKE_MAS2(epn, wimge); + UInt32 mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); + UInt32 mas7 = FSL_BOOKE_MAS7(rpn); + + hal_write_tlb(mas0, mas1, mas2, mas3, mas7); + + return true; +} + +/// @brief Flush TLB +EXTERN_C void hal_flush_tlb() +{ + asm volatile("isync;tlbwe;msync;isync"); +} diff --git a/dev/kernel/HALKit/POWER/MBCI/.gitkeep b/dev/kernel/HALKit/POWER/MBCI/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/POWER/MBCI/.gitkeep diff --git a/dev/kernel/HALKit/POWER/MBCI/HalMBCIHost.cc b/dev/kernel/HALKit/POWER/MBCI/HalMBCIHost.cc new file mode 100644 index 00000000..0d2e140b --- /dev/null +++ b/dev/kernel/HALKit/POWER/MBCI/HalMBCIHost.cc @@ -0,0 +1,8 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> diff --git a/dev/kernel/HALKit/POWER/Processor.h b/dev/kernel/HALKit/POWER/Processor.h new file mode 100644 index 00000000..bbcfd01f --- /dev/null +++ b/dev/kernel/HALKit/POWER/Processor.h @@ -0,0 +1,62 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + Purpose: POWER processor header. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/Utils.h> + +#define NoOp() asm volatile("mr 0, 0") +#define kHalPPCAlignment __attribute__((aligned(4))) + +namespace NeOS::HAL +{ + typedef UIntPtr Reg; + + /// @brief Stack frame (as retrieved from assembly.) + struct PACKED StackFrame final + { + Reg R8{0}; + Reg R9{0}; + Reg R10{0}; + Reg R11{0}; + Reg R12{0}; + Reg R13{0}; + Reg R14{0}; + Reg R15{0}; + Reg SP{0}; + Reg BP{0}; + }; + + typedef StackFrame* StackFramePtr; + + inline void rt_halt() + { + while (true) + { + NoOp(); // no oop. + } + } + + inline void rt_cli() + { + NoOp(); // no oop + } +} // namespace NeOS::HAL + +EXTERN_C NeOS::Void int_handle_math(NeOS::UIntPtr sp); +EXTERN_C NeOS::Void int_handle_pf(NeOS::UIntPtr sp); + +/// @brief Set TLB. +NeOS::Bool hal_set_tlb(NeOS::UInt8 tlb, NeOS::UInt32 epn, NeOS::UInt64 rpn, NeOS::UInt8 perms, NeOS::UInt8 wimge, NeOS::UInt8 ts, NeOS::UInt8 esel, NeOS::UInt8 tsize, NeOS::UInt8 iprot); + +/// @brief Write TLB. +NeOS::Void hal_write_tlb(NeOS::UInt32 mas0, NeOS::UInt32 mas1, NeOS::UInt32 mas2, NeOS::UInt32 mas3, NeOS::UInt32 mas7); + +/// @brief Flush TLB. +EXTERN_C NeOS::Void hal_flush_tlb(); diff --git a/dev/kernel/HALKit/POWER/ReadMe.md b/dev/kernel/HALKit/POWER/ReadMe.md new file mode 100644 index 00000000..a9751581 --- /dev/null +++ b/dev/kernel/HALKit/POWER/ReadMe.md @@ -0,0 +1,4 @@ +POWER Hardware Abstraction Layer + +- Supported CPU: POWER +- Supported Firmware: CoreBoot
\ No newline at end of file diff --git a/dev/kernel/HALKit/RISCV/.keep b/dev/kernel/HALKit/RISCV/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/RISCV/.keep diff --git a/dev/kernel/HALKit/RISCV/AP.h b/dev/kernel/HALKit/RISCV/AP.h new file mode 100644 index 00000000..c198a404 --- /dev/null +++ b/dev/kernel/HALKit/RISCV/AP.h @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: AP.h + Purpose: RISC-V hardware threads. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + typedef Int64 hal_ap_kind; + + typedef struct HAL_HARDWARE_THREAD + { + NeOS::UIntPtr fStartAddress; + NeOS::UInt8 fPrivleged : 1; + NeOS::UInt32 fPageMemoryFlags; + hal_ap_kind fIdentNumber; + } HAL_HARDWARE_THREAD; + + /// @brief Set PC to specific hart. + /// @param hart the hart + /// @param epc the pc. + /// @return + EXTERN_C NeOS::Void hal_set_pc_to_hart(HAL_HARDWARE_THREAD* hart, NeOS::VoidPtr epc); +} // namespace NeOS diff --git a/dev/kernel/HALKit/RISCV/APM/.gitkeep b/dev/kernel/HALKit/RISCV/APM/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/RISCV/APM/.gitkeep diff --git a/dev/kernel/HALKit/RISCV/HalAP.cc b/dev/kernel/HALKit/RISCV/HalAP.cc new file mode 100644 index 00000000..788acf0f --- /dev/null +++ b/dev/kernel/HALKit/RISCV/HalAP.cc @@ -0,0 +1,40 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/RISCV/Processor.h>
+#include <KernelKit/DebugOutput.h>
+#include <HALKit/RISCV/AP.h>
+
+using namespace NeOS;
+
+namespace NeOS::Detail
+{
+ STATIC void mp_hang_fn(void)
+ {
+ while (YES)
+ ;
+ }
+} // namespace NeOS::Detail
+
+/// @brief wakes up thread.
+/// wakes up thread from hang.
+void mp_wakeup_thread(HAL::StackFramePtr stack)
+{
+ if (!stack)
+ return;
+
+ hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(stack->BP));
+}
+
+/// @brief makes thread sleep.
+/// hooks and hangs thread to prevent code from executing.
+void mp_hang_thread(HAL::StackFramePtr stack)
+{
+ if (!stack)
+ return;
+
+ hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(NeOS::Detail::mp_hang_fn));
+}
diff --git a/dev/kernel/HALKit/RISCV/ReadMe.md b/dev/kernel/HALKit/RISCV/ReadMe.md new file mode 100644 index 00000000..b099aa31 --- /dev/null +++ b/dev/kernel/HALKit/RISCV/ReadMe.md @@ -0,0 +1,4 @@ +RISCV64 Hardware Abstraction Layer + +- Supported CPU: RISCV64 +- Supported Firmware: CoreBoot
\ No newline at end of file diff --git a/dev/kernel/HALKit/RISCV/Storage/.gitkeep b/dev/kernel/HALKit/RISCV/Storage/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/RISCV/Storage/.gitkeep diff --git a/dev/kernel/HALKit/X86S/.gitkeep b/dev/kernel/HALKit/X86S/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/X86S/.gitkeep diff --git a/dev/kernel/HALKit/X86S/ACPI/.gitkeep b/dev/kernel/HALKit/X86S/ACPI/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/X86S/ACPI/.gitkeep diff --git a/dev/kernel/HALKit/X86S/Storage/.gitkeep b/dev/kernel/HALKit/X86S/Storage/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/X86S/Storage/.gitkeep |
