summaryrefslogtreecommitdiffhomepage
path: root/dev/Kernel/HALKit/AMD64/Processor.h
diff options
context:
space:
mode:
Diffstat (limited to 'dev/Kernel/HALKit/AMD64/Processor.h')
-rw-r--r--dev/Kernel/HALKit/AMD64/Processor.h326
1 files changed, 326 insertions, 0 deletions
diff --git a/dev/Kernel/HALKit/AMD64/Processor.h b/dev/Kernel/HALKit/AMD64/Processor.h
new file mode 100644
index 00000000..0e6dcfff
--- /dev/null
+++ b/dev/Kernel/HALKit/AMD64/Processor.h
@@ -0,0 +1,326 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024, 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 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 = 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);
+ }
+
+ /***********************************************************************************/
+ /// @brief Get Model specific register inside core.
+ /// @param msr MSR
+ /// @param lo low byte
+ /// @param hi high byte
+ /***********************************************************************************/
+ inline Void hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) noexcept
+ {
+ if (!lo || !hi)
+ return;
+
+ asm volatile("rdmsr"
+ : "=a"(*lo), "=d"(*hi)
+ : "c"(msr));
+ }
+
+ /// @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 ZKA_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 ZKA_GDT_ENTRY final
+ {
+ UInt16 fLimitLow;
+ UInt16 fBaseLow;
+ UInt8 fBaseMid;
+ UInt8 fAccessByte;
+ UInt8 fFlags;
+ UInt8 fBaseHigh;
+ };
+ } // namespace Detail
+
+ class APICController
+ {
+ public:
+ explicit APICController(VoidPtr base)
+ : fApic(base)
+ {
+ }
+
+ ~APICController() = default;
+
+ ZKA_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 virt_addr, 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 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::RegisterGDT ptr);
+
+inline Kernel::VoidPtr kKernelBitMpStart = nullptr;
+inline Kernel::UIntPtr kKernelBitMpSize = 0UL;