diff options
Diffstat (limited to 'src/kernel/HALKit/AMD64/Processor.h')
| -rw-r--r-- | src/kernel/HALKit/AMD64/Processor.h | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/kernel/HALKit/AMD64/Processor.h b/src/kernel/HALKit/AMD64/Processor.h new file mode 100644 index 00000000..db1ed573 --- /dev/null +++ b/src/kernel/HALKit/AMD64/Processor.h @@ -0,0 +1,283 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: Prcoessor.h + Purpose: AMD64 processor abstraction. + + Revision History: + + 30/01/24: Added file (amlel) + +======================================== */ + +#pragma once + +#ifdef __NE_AMD64__ + +#include <FirmwareKit/Handover.h> +#include <HALKit/AMD64/Paging.h> +#include <NeKit/Array.h> +#include <NeKit/Defines.h> +#include <NeKit/Utils.h> + +#include <HALKit/AMD64/CPUID.h> + +#define kPITControlPort (0x43) +#define kPITChannel0Port (0x40) +#define kPITFrequency (1193180) + +#define kPICCommand (0x20) +#define kPICData (0x21) +#define kPIC2Command (0xA0) +#define kPIC2Data (0xA1) + +#define kIOAPICRegVal (4) +#define kIOAPICRegReg (0) + +#define rtl_nop_op() asm volatile("nop") + +/// @brief Maximum entries of the interrupt descriptor table. +#define kKernelIdtSize (0x100) + +/// @brief interrupt for system call. +#define kKernelInterruptId (0x32) + +#define IsActiveLow(FLG) (FLG & 2) +#define IsLevelTriggered(FLG) (FLG & 8) + +#define kInterruptGate (0x8E) +#define kUserInterruptGate (0xEE) +#define kTrapGate (0xEF) +#define kTaskGate (0b10001100) +#define kIDTSelector (0x08) + +namespace Kernel { +namespace Detail::AMD64 { + struct PACKED InterruptDescriptorAMD64 final { + UInt16 OffsetLow; // offset bits 0..15 + UInt16 Selector; // a code segment selector in GDT or LDT + UInt8 Ist; + UInt8 TypeAttributes; + UInt16 OffsetMid; + UInt32 OffsetHigh; + UInt32 Zero; // reserved + }; +} // namespace Detail::AMD64 +} // namespace Kernel + +namespace Kernel::HAL { +/// @brief Memory Manager mapping flags. +enum { + kMMFlagsInvalid = 1 << 0, + kMMFlagsPresent = 1 << 1, + kMMFlagsWr = 1 << 2, + kMMFlagsUser = 1 << 3, + kMMFlagsNX = 1 << 4, + kMMFlagsPCD = 1 << 5, + kMMFlagsPwt = 1 << 6, + kMMFlagsCount = 6, +}; + +struct PACKED Register64 final { + UShort Limit; + UIntPtr Base; +}; + +using RawRegister = UInt64; +using Reg = RawRegister; +using InterruptId = UInt16; /* For each element in the IVT */ + +/// @brief Stack frame (as retrieved from assembly.) +struct PACKED StackFrame { + Reg IP; + Reg SP; + Reg R8; + Reg R9; + Reg R10; + Reg R11; + Reg R12; + Reg R13; + Reg R14; + Reg R15; +}; + +typedef StackFrame* StackFramePtr; + +class InterruptDescriptor final { + public: + UShort Offset; + UShort Selector; + UChar Ist; + UChar Atrributes; + + UShort SecondOffset; + UInt ThirdOffset; + UInt Zero; + + operator bool() { return Offset != 0xFFFF; } +}; + +using InterruptDescriptorArray = Array<InterruptDescriptor, 256>; + +class SegmentDescriptor final { + public: + UInt16 Base; + UInt8 BaseMiddle; + UInt8 BaseHigh; + + UShort Limit; + UChar Gran; + UChar AccessByte; +}; + +/*** + * @brief Segment Boolean operations + */ +class SegmentDescriptorComparator final { + public: + Bool IsValid(SegmentDescriptor& seg) { return seg.Base > seg.Limit; } + + Bool Equals(SegmentDescriptor& seg, SegmentDescriptor& segRight) { + return seg.Base == segRight.Base && seg.Limit == segRight.Limit; + } +}; + +using SegmentArray = Array<SegmentDescriptor, 6>; + +class GDTLoader final { + public: + static Void Load(Register64& gdt); + static Void Load(Ref<Register64>& gdt); +}; + +class IDTLoader final { + public: + static Void Load(Register64& idt); + static Void Load(Ref<Register64>& idt); +}; + +/***********************************************************************************/ +/// @brief Is the current config SMP aware? +/// @return True if YES, False if not. +/***********************************************************************************/ + +Bool mp_is_smp(Void) noexcept; + +/***********************************************************************************/ +/// @brief Fetch and enable SMP scheduler. +/// @param vendor_ptr SMP containing structure. +/***********************************************************************************/ +Void mp_init_cores(VoidPtr vendor_ptr) noexcept; + +/***********************************************************************************/ +/// @brief Do a cpuid to check if MSR exists on CPU. +/// @retval true it does exists. +/// @retval false it doesn't. +/***********************************************************************************/ +Bool hal_has_msr() noexcept; + +/***********************************************************************************/ +/// @brief Get Model specific register inside core. +/// @param msr MSR +/// @param lo low byte +/// @param hi high byte +/***********************************************************************************/ +Void hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) noexcept; + +/// @brief Set Model-specific register. +/// @param msr MSR +/// @param lo low byte +/// @param hi high byte +Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) noexcept; + +/// @brief Processor specific namespace. +namespace Detail { + /* @brief TSS struct. */ + struct NE_TSS final { + UInt32 fReserved1; + UInt64 fRsp0; + UInt64 fRsp1; + UInt64 fRsp2; + UInt64 fReserved2; + UInt64 fIst1; + UInt64 fIst2; + UInt64 fIst3; + UInt64 fIst4; + UInt64 fIst5; + UInt64 fIst6; + UInt64 fIst7; + UInt64 fReserved3; + UInt16 fReserved4; + UInt16 fIopb; + }; + + /** + @brief Global descriptor table entry, either null, code or data. + */ + + struct PACKED NE_GDT_ENTRY final { + UInt16 fLimitLow; + UInt16 fBaseLow; + UInt8 fBaseMid; + UInt8 fAccessByte; + UInt8 fFlags; + UInt8 fBaseHigh; + }; +} // namespace Detail + +class LAPICDmaWrapper final { + public: + explicit LAPICDmaWrapper(VoidPtr base); + ~LAPICDmaWrapper(); + + NE_COPY_DEFAULT(LAPICDmaWrapper) + + public: + UInt32 Read(UInt16 reg) noexcept; + Void Write(UInt16 reg, UInt32 value) noexcept; + + private: + VoidPtr fApic{nullptr}; +}; + +/// @brief Set a PTE from pd_base. +/// @param virt_addr a valid virtual address. +/// @param phys_addr point to physical address. +/// @param flags the flags to put on the page. +/// @return Status code of page manip. +EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags, + UInt32 level = 2); + +EXTERN_C UInt8 rt_in8(UInt16 port); +EXTERN_C UInt16 rt_in16(UInt16 port); +EXTERN_C UInt32 rt_in32(UInt16 port); + +EXTERN_C Void rt_out16(UShort port, UShort byte); +EXTERN_C Void rt_out8(UShort port, UChar byte); +EXTERN_C Void rt_out32(UShort port, UInt byte); + +EXTERN_C Void rt_wait_400ns(); +EXTERN_C Void rt_halt(); +EXTERN_C Void rt_cli(); +EXTERN_C Void rt_sti(); +EXTERN_C Void rt_cld(); +EXTERN_C Void rt_std(); + +EXTERN_C UIntPtr mm_get_page_addr(VoidPtr virtual_address); + +EXTERN_C Int32 mm_memory_fence(VoidPtr virtual_address); +} // namespace Kernel::HAL + +EXTERN_C Kernel::Void idt_handle_generic(Kernel::UIntPtr rsp); +EXTERN_C Kernel::Void idt_handle_gpf(Kernel::UIntPtr rsp); +EXTERN_C Kernel::Void idt_handle_math(Kernel::UIntPtr rsp); +EXTERN_C Kernel::Void idt_handle_pf(Kernel::UIntPtr rsp); + +EXTERN_C ATTRIBUTE(naked) Kernel::Void hal_load_idt(Kernel::HAL::Register64 ptr); +EXTERN_C ATTRIBUTE(naked) Kernel::Void hal_load_gdt(Kernel::HAL::Register64 ptr); + +inline Kernel::VoidPtr kKernelBitMpStart = nullptr; +inline Kernel::UIntPtr kKernelBitMpSize = 0UL; + +#endif // __NE_AMD64__ */
\ No newline at end of file |
