// SPDX-License-Identifier: Apache-2.0 // Copyright 2024-2026, Amlal El Mahrouss (amlal@nekernel.org) // Licensed under the Apache License, Version 2.0 (see LICENSE file) // Official repository: https://github.com/ne-foss-org/nekernel #ifndef HALKIT_PROCESSOR_H #define HALKIT_PROCESSOR_H #ifdef __NE_AMD64__ #include #include #include #include #include #include #define kPITControlPort (0x43) #define kPITChannel0Port (0x40) #define kPITFrequency (1193180) #define kPICCommand (0x20) #define kPICData (0x21) #define kPIC2Command (0xA0) #define kPIC2Data (0xA1) #define kIOAPICRegVal (4) #define kIOAPICRegReg (0) #define rtl_nop_op() asm volatile("nop") /// @brief Maximum entries of the interrupt descriptor table. #define kKernelIdtSize (0x100) /// @brief interrupt for system call. #define kKernelInterruptId (0x32) #define IsActiveLow(FLG) (FLG & 2) #define IsLevelTriggered(FLG) (FLG & 8) #define kInterruptGate (0x8E) #define kUserInterruptGate (0xEE) #define kTrapGate (0xEF) #define kTaskGate (0b10001100) #define kIDTSelector (0x08) namespace Kernel { namespace Detail::AMD64 { struct PACKED InterruptDescriptorAMD64 final { UInt16 OffsetLow; // offset bits 0..15 UInt16 Selector; // a code segment selector in GDT or LDT UInt8 Ist; UInt8 TypeAttributes; UInt16 OffsetMid; UInt32 OffsetHigh; UInt32 Zero; // reserved }; } // namespace Detail::AMD64 } // namespace Kernel namespace Kernel::HAL { /// @brief Memory Manager mapping flags. enum { kMMFlagsInvalid = 1 << 0, kMMFlagsPresent = 1 << 1, kMMFlagsWr = 1 << 2, kMMFlagsUser = 1 << 3, kMMFlagsNX = 1 << 4, kMMFlagsPCD = 1 << 5, kMMFlagsPwt = 1 << 6, kMMFlagsCount = 6, }; struct PACKED Register64 final { UShort Limit; UIntPtr Base; }; using RawRegister = UInt64; using Reg = RawRegister; using InterruptId = UInt16; /* For each element in the IVT */ /// @brief Stack frame (as retrieved from assembly.) struct PACKED StackFrame { Reg IP; Reg SP; Reg R8; Reg R9; Reg R10; Reg R11; Reg R12; Reg R13; Reg R14; Reg R15; }; typedef StackFrame* StackFramePtr; class InterruptDescriptor final { public: UShort Offset; UShort Selector; UChar Ist; UChar Atrributes; UShort SecondOffset; UInt ThirdOffset; UInt Zero; operator bool() { return Offset != 0xFFFF; } }; using InterruptDescriptorArray = Array; 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; class GDTLoader final { public: static Void Load(Register64& gdt); static Void Load(Ref& gdt); }; class IDTLoader final { public: static Void Load(Register64& idt); static Void Load(Ref& idt); }; /***********************************************************************************/ /// @brief Is the current config SMP aware? /// @return True if YES, False if not. /***********************************************************************************/ Bool mp_is_smp(Void); /***********************************************************************************/ /// @brief Fetch and enable SMP scheduler. /// @param vendor_ptr SMP containing structure. /***********************************************************************************/ Void mp_init_cores(VoidPtr vendor_ptr); /***********************************************************************************/ /// @brief Do a cpuid to check if MSR exists on CPU. /// @retval true it does exists. /// @retval false it doesn't. /***********************************************************************************/ Bool hal_has_msr(); /***********************************************************************************/ /// @brief Get Model specific register inside core. /// @param msr MSR /// @param lo low byte /// @param hi high byte /***********************************************************************************/ Void hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi); /// @brief Set Model-specific register. /// @param msr MSR /// @param lo low byte /// @param hi high byte Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi); /// @brief Processor specific namespace. namespace Detail { /* @brief TSS struct. */ struct NE_TSS final { UInt32 fReserved1; UInt64 fRsp0; UInt64 fRsp1; UInt64 fRsp2; UInt64 fReserved2; UInt64 fIst1; UInt64 fIst2; UInt64 fIst3; UInt64 fIst4; UInt64 fIst5; UInt64 fIst6; UInt64 fIst7; UInt64 fReserved3; UInt16 fReserved4; UInt16 fIopb; }; /** @brief Global descriptor table entry, either null, code or data. */ struct PACKED NE_GDT_ENTRY final { UInt16 fLimitLow; UInt16 fBaseLow; UInt8 fBaseMid; UInt8 fAccessByte; UInt8 fFlags; UInt8 fBaseHigh; }; } // namespace Detail class LAPICDmaWrapper final { public: explicit LAPICDmaWrapper(VoidPtr base); ~LAPICDmaWrapper(); NE_COPY_DEFAULT(LAPICDmaWrapper) public: UInt32 Read(UInt16 reg); Void Write(UInt16 reg, UInt32 value); private: VoidPtr fApic{nullptr}; }; /// @brief Set a PTE from pd_base. /// @param virt_addr a valid virtual address. /// @param phys_addr point to physical address. /// @param flags the flags to put on the page. /// @return Status code of page manip. EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, UInt32 level = 2); EXTERN_C UInt8 rt_in8(UInt16 port); EXTERN_C UInt16 rt_in16(UInt16 port); EXTERN_C UInt32 rt_in32(UInt16 port); EXTERN_C Void rt_out16(UShort port, UShort byte); EXTERN_C Void rt_out8(UShort port, UChar byte); EXTERN_C Void rt_out32(UShort port, UInt byte); EXTERN_C Void rt_wait_400ns(); EXTERN_C Void rt_halt(); EXTERN_C Void rt_cli(); EXTERN_C Void rt_sti(); EXTERN_C Void rt_cld(); EXTERN_C Void rt_std(); EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virtual_address); EXTERN_C Int32 mm_memory_fence(VoidPtr virtual_address); } // namespace Kernel::HAL EXTERN_C Kernel::Void idt_handle_generic(Kernel::UIntPtr rsp); EXTERN_C Kernel::Void idt_handle_gpf(Kernel::UIntPtr rsp); EXTERN_C Kernel::Void idt_handle_math(Kernel::UIntPtr rsp); EXTERN_C Kernel::Void idt_handle_pf(Kernel::UIntPtr rsp); EXTERN_C ATTRIBUTE(naked) Kernel::Void hal_load_idt(Kernel::HAL::Register64 ptr); EXTERN_C ATTRIBUTE(naked) Kernel::Void hal_load_gdt(Kernel::HAL::Register64 ptr); inline Kernel::VoidPtr kKernelBitMpStart = nullptr; inline Kernel::SizeT kKernelBitMpSize = 0UL; #endif // __NE_AMD64__ */ #endif