From ad9817a2db61cf44b4dbac29b91502e2261395aa Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 11 Oct 2022 02:43:23 +0300 Subject: [PATCH] Added APIC & SMP stub --- .../amd64/MultipleAPICDescriptionTable.cpp | 12 +- Architecture/amd64/acpi.hpp | 6 +- ...dvancedProgrammableInterruptController.cpp | 202 ++++++++ Architecture/amd64/cpu/SMPTrampoline.asm | 113 +++++ .../amd64/cpu/SymmetricMultiprocessing.cpp | 26 + Architecture/amd64/cpu/apic.hpp | 64 +++ Core/Interrupts/IntManager.cpp | 22 +- Kernel.cpp | 11 +- include/cpu.hpp | 473 ++++++++++++++++++ include/smp.hpp | 35 ++ 10 files changed, 953 insertions(+), 11 deletions(-) create mode 100644 Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp create mode 100644 Architecture/amd64/cpu/SMPTrampoline.asm create mode 100644 Architecture/amd64/cpu/SymmetricMultiprocessing.cpp create mode 100644 Architecture/amd64/cpu/apic.hpp create mode 100644 include/smp.hpp diff --git a/Architecture/amd64/MultipleAPICDescriptionTable.cpp b/Architecture/amd64/MultipleAPICDescriptionTable.cpp index d170380..4974e7f 100644 --- a/Architecture/amd64/MultipleAPICDescriptionTable.cpp +++ b/Architecture/amd64/MultipleAPICDescriptionTable.cpp @@ -7,7 +7,7 @@ namespace ACPI { MADT::MADT(ACPI::MADTHeader *madt) { - LAPICAddr = (LAPIC *)(uintptr_t)madt->LocalControllerAddress; + LAPICAddress = (LAPIC *)(uintptr_t)madt->LocalControllerAddress; for (uint8_t *ptr = (uint8_t *)(madt->Entries); (uintptr_t)(ptr) < (uintptr_t)(madt) + madt->Header.Length; ptr += *(ptr + 1)) @@ -27,8 +27,8 @@ namespace ACPI case 1: { ioapic.push_back((MADTIOApic *)ptr); - trace("I/O APIC %#llx (Address %#llx) found.", ioapic.back()->APICID, ioapic.back()->addr); - Memory::Virtual().Map((void *)(uintptr_t)ioapic.back()->addr, (void *)(uintptr_t)ioapic.back()->addr, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped. + trace("I/O APIC %#llx (Address %#llx) found.", ioapic.back()->APICID, ioapic.back()->Address); + Memory::Virtual().Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped. break; } case 2: @@ -48,12 +48,12 @@ namespace ACPI } case 5: { - LAPICAddr = (LAPIC *)ptr; - trace("APIC found at %#llx", LAPICAddr); + LAPICAddress = (LAPIC *)ptr; + trace("APIC found at %#llx", LAPICAddress); break; } } - Memory::Virtual().Map((void *)LAPICAddr, (void *)LAPICAddr, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page? + Memory::Virtual().Map((void *)LAPICAddress, (void *)LAPICAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page? } trace("Total CPU cores: %d", CPUCores); } diff --git a/Architecture/amd64/acpi.hpp b/Architecture/amd64/acpi.hpp index fcb604d..40b2f8b 100644 --- a/Architecture/amd64/acpi.hpp +++ b/Architecture/amd64/acpi.hpp @@ -199,8 +199,8 @@ namespace ACPI struct APICHeader Header; uint8_t APICID; uint8_t reserved; - uint32_t addr; - uint32_t gsib; + uint32_t Address; + uint32_t GSIBase; } __attribute__((packed)); struct MADTIso @@ -239,7 +239,7 @@ namespace ACPI Vector iso; Vector nmi; Vector lapic; - struct LAPIC *LAPICAddr; + struct LAPIC *LAPICAddress; uint8_t CPUCores; MADT(ACPI::MADTHeader *madt); diff --git a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp new file mode 100644 index 0000000..66bdd01 --- /dev/null +++ b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp @@ -0,0 +1,202 @@ +#include "apic.hpp" + +#include +#include + +#include "../../../kernel.h" +#include "../acpi.hpp" + +namespace APIC +{ + enum IOAPICRegisters + { + GetIOAPICVersion = 0x1 + }; + + enum IOAPICFlags + { + ActiveHighLow = 2, + EdgeLevel = 8 + }; + + struct IOAPICVersion + { + uint8_t Version; + uint8_t Reserved; + uint8_t MaximumRedirectionEntry; + uint8_t Reserved2; + }; + + // headache + // https://www.amd.com/system/files/TechDocs/24593.pdf + // https://www.naic.edu/~phil/software/intel/318148.pdf + + uint32_t APIC::Read(uint32_t Register) + { + // Too repetitive + if (Register != APIC_EOI && + Register != APIC_ID && + Register != APIC_TIMER && + Register != APIC_TDCR && + Register != APIC_TICR && + Register != APIC_TCCR) + debug("APIC::Read(%#lx)", Register); + if (x2APICSupported) + { + if (Register != APIC_ICRHI) + return CPU::x64::rdmsr((Register >> 4) + 0x800); + else + return CPU::x64::rdmsr(0x30 + 0x800); + } + else + return *((volatile uint32_t *)((uintptr_t)((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress + Register)); + } + + void APIC::Write(uint32_t Register, uint32_t Value) + { + // Too repetitive + if (Register != APIC_EOI && + Register != APIC_TIMER && + Register != APIC_TDCR && + Register != APIC_TICR && + Register != APIC_TCCR) + debug("APIC::Write(%#lx, %#lx)", Register, Value); + if (x2APICSupported) + { + if (Register != APIC_ICRHI) + CPU::x64::wrmsr((Register >> 4) + 0x800, Value); + else + CPU::x64::wrmsr(CPU::x64::MSR_X2APIC_ICR, Value); + } + else + *((volatile uint32_t *)(((uintptr_t)((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress) + Register)) = Value; + } + + void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value) + { + debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value); + *((volatile uint32_t *)(((uintptr_t)Base))) = Register; + *((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value; + } + + uint32_t APIC::IORead(uint64_t Base, uint32_t Register) + { + debug("APIC::IORead(%#lx, %#lx)", Base, Register); + *((volatile uint32_t *)(((uintptr_t)Base))) = Register; + return *((volatile uint32_t *)(((uintptr_t)Base + 16))); + } + + void APIC::EOI() { this->Write(APIC_EOI, 0); } + + void APIC::RedirectIRQs(int CPU) + { + debug("Redirecting IRQs..."); + for (int i = 0; i < 16; i++) + this->RedirectIRQ(CPU, i, 1); + debug("Redirecting IRQs completed."); + } + + void APIC::IPI(uint8_t CPU, uint32_t InterruptNumber) + { + if (x2APICSupported) + { + CPU::x64::wrmsr(CPU::x64::MSR_X2APIC_ICR, ((uint64_t)CPU) << 32 | InterruptNumber); + } + else + { + InterruptNumber = (1 << 14) | InterruptNumber; + this->Write(APIC_ICRHI, (CPU << 24)); + this->Write(APIC_ICRLO, InterruptNumber); + } + } + + void APIC::OneShot(uint32_t Vector, uint64_t Miliseconds) + { + int apic_timer_ticks = 0; + fixme("APIC::OneShot(%#lx, %#lx)", Vector, Miliseconds); + this->Write(APIC_TDCR, 0x03); + this->Write(APIC_TIMER, (APIC::APIC::APICRegisters::APIC_ONESHOT | Vector)); + this->Write(APIC_TICR, apic_timer_ticks * Miliseconds); + } + + uint32_t APIC::IOGetMaxRedirect(uint32_t APICID) + { + uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion)); + return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry; + } + + void APIC::RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status) + { + uint64_t Value = Vector; + + int64_t IOAPICTarget = -1; + for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++) + if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI) + if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(i) > GSI) + { + IOAPICTarget = i; + break; + } + + if (IOAPICTarget == -1) + { + error("No ISO table found for I/O APIC"); + return; + } + + if (Flags & ActiveHighLow) + Value |= (1 << 13); + + if (Flags & EdgeLevel) + Value |= (1 << 15); + + if (!Status) + Value |= (1 << 16); + + Value |= (((uintptr_t)GetCPU(CPU)->Data->LAPIC.APICId) << 56); + uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16; + + this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value); + this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32)); + } + + void APIC::RedirectIRQ(int CPU, uint8_t IRQ, int Status) + { + for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++) + if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ) + { + debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d", + i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU); + + this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status); + return; + } + debug("Mapping IRQ%d on CPU %d", IRQ, CPU); + this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status); + } + + APIC::APIC() + { + uint32_t rcx; + CPU::x64::cpuid(1, 0, 0, &rcx, 0); + if (rcx & CPU::x64::CPUID_FEAT_RCX_x2APIC) + { + // this->x2APICSupported = true; + warn("x2APIC not supported yet."); + // CPU::x64::wrmsr(CPU::x64::MSR_APIC_BASE, (CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10)); + CPU::x64::wrmsr(CPU::x64::MSR_APIC_BASE, CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE) | (1 << 11)); + } + else + { + CPU::x64::wrmsr(CPU::x64::MSR_APIC_BASE, CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE) | (1 << 11)); + } + trace("APIC Address: %#lx", CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE)); + + this->Write(APIC_TPR, 0x0); + this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100 + } + + APIC::~APIC() + { + } +} diff --git a/Architecture/amd64/cpu/SMPTrampoline.asm b/Architecture/amd64/cpu/SMPTrampoline.asm new file mode 100644 index 0000000..fa1317e --- /dev/null +++ b/Architecture/amd64/cpu/SMPTrampoline.asm @@ -0,0 +1,113 @@ +[bits 16] +TRAMPOLINE_BASE equ 0x2000 + +extern StartCPU +global _trampoline_start +_trampoline_start: + cli + mov ax, 0x0 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + o32 lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_BASE] + mov eax, cr0 + or al, 0x1 + mov cr0, eax + jmp 0x8:(Trampoline32 - _trampoline_start + TRAMPOLINE_BASE) + +[bits 32] +section .text +Trampoline32: + mov bx, 0x10 + mov ds, bx + mov es, bx + mov ss, bx + mov eax, dword [0x500] + mov cr3, eax + mov eax, cr4 + or eax, 1 << 5 ; Set the PAE-bit, which is the 6th bit (bit 5). + or eax, 1 << 7 + mov cr4, eax + mov ecx, 0xc0000080 + rdmsr + or eax,1 << 8 ; LME + wrmsr + mov eax, cr0 + or eax, 1 << 31 + mov cr0, eax + lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_BASE] + jmp 0x8:(Trampoline64 - _trampoline_start + TRAMPOLINE_BASE) + +[bits 64] +Trampoline64: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov ss, ax + mov ax, 0x0 + mov fs, ax + mov gs, ax + lgdt [0x580] + lidt [0x590] + mov rsp, [0x570] + mov rbp, 0x0 ; Terminate stack traces here. + ; Reset RFLAGS. + push 0x0 + popf + mov rax, qword vcode64 + call vcode64 + +vcode64: + push rbp + ; Set up SSE + mov rax, cr0 + ; btr eax, 2 + ; bts eax, 1 + ; mov cr0, rax + mov rax, cr4 + bts eax, 9 + bts eax, 10 + mov cr4, rax + mov rax, qword TrampolineExit + call rax + +align 16 +LongMode_gdtr: + dw LongModeGDTEnd - LongModeGDTStart - 1 + dq LongModeGDTStart - _trampoline_start + TRAMPOLINE_BASE + +align 16 +LongModeGDTStart: + dq 0 ; NULL segment + dq 0x00AF98000000FFFF ; Code segment + dq 0x00CF92000000FFFF ; Data segment +LongModeGDTEnd: + +align 16 +ProtectedMode_gdtr: + dw ProtectedModeGDTEnd - ProtectedModeGDTStart - 1 + dd ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_BASE + +align 16 +ProtectedModeGDTStart: + dq 0 ; NULL segment + dq 0x00CF9A000000FFFF ; Code segment + dq 0x00CF92000000FFFF ; Data segment +ProtectedModeGDTEnd: + +align 16 +ProtectedMode_idtr: + dw 0 + dd 0 + dd 0 + align 16 + +global _trampoline_end +_trampoline_end: + +TrampolineExit: + call StartCPU + +times 512 - ($-$$) db 0 diff --git a/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp b/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp new file mode 100644 index 0000000..c0af3cc --- /dev/null +++ b/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp @@ -0,0 +1,26 @@ +#include + +#include + +#include "../../../kernel.h" + +extern "C" uint64_t _trampoline_start, _trampoline_end; + +#define TRAMPOLINE_START 0x2000 + +enum SMPTrampolineAddress +{ + PAGE_TABLE = 0x500, + START_ADDR = 0x520, + STACK = 0x570, + GDT = 0x580, + IDT = 0x590, +}; + +volatile bool CPUEnabled = false; + +extern "C" void StartCPU() +{ + CPUEnabled = true; + CPU::Stop(); +} diff --git a/Architecture/amd64/cpu/apic.hpp b/Architecture/amd64/cpu/apic.hpp new file mode 100644 index 0000000..6681112 --- /dev/null +++ b/Architecture/amd64/cpu/apic.hpp @@ -0,0 +1,64 @@ +#ifndef __FENNIX_KERNEL_APIC_H__ +#define __FENNIX_KERNEL_APIC_H__ + +#include + +namespace APIC +{ + class APIC + { + private: + bool x2APICSupported = false; + + public: + enum APICRegisters + { + APIC_ONESHOT = (0 << 17), // LVT One-Shot Mode (for Timer) + APIC_PERIODIC = (1 << 17), // LVT Periodic Mode (for Timer) + APIC_TSC_DEADLINE = (2 << 17), // LVT Timer/sDeadline (for Timer) + // source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c + APIC_ID = 0x20, // Local APIC ID + APIC_VER = 0x30, // Local APIC Version + APIC_TPR = 0x80, // Task Priority + APIC_APR = 0x90, // Arbitration Priority + APIC_PPR = 0xa0, // Processor Priority + APIC_EOI = 0xb0, // EOI + APIC_RRD = 0xc0, // Remote Read + APIC_LDR = 0xd0, // Logical Destination + APIC_DFR = 0xe0, // Destination Format + APIC_SVR = 0xf0, // Spurious Interrupt Vector + APIC_ISR = 0x100, // In-Service (8 registers) + APIC_TMR = 0x180, // Trigger Mode (8 registers) + APIC_IRR = 0x200, // Interrupt Request (8 registers) + APIC_ESR = 0x280, // Error Status + APIC_ICRLO = 0x300, // Interrupt Command + APIC_ICRHI = 0x310, // Interrupt Command [63:32] + APIC_TIMER = 0x320, // LVT Timer + APIC_THERMAL = 0x330, // LVT Thermal Sensor + APIC_PERF = 0x340, // LVT Performance Counter + APIC_LINT0 = 0x350, // LVT LINT0 + APIC_LINT1 = 0x360, // LVT LINT1 + APIC_ERROR = 0x370, // LVT Error + APIC_TICR = 0x380, // Initial Count (for Timer) + APIC_TCCR = 0x390, // Current Count (for Timer) + APIC_TDCR = 0x3e0, // Divide Configuration (for Timer) + }; + + uint32_t Read(uint32_t Register); + void Write(uint32_t Register, uint32_t Value); + void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value); + uint32_t IORead(uint64_t Base, uint32_t Register); + void EOI(); + void RedirectIRQs(int CPU = 0); + void IPI(uint8_t CPU, uint32_t InterruptNumber); + void OneShot(uint32_t Vector, uint64_t Miliseconds); + bool APICSupported(); + uint32_t IOGetMaxRedirect(uint32_t APICID); + void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status); + void RedirectIRQ(int CPU, uint8_t IRQ, int Status); + APIC(); + ~APIC(); + }; +} + +#endif // !__FENNIX_KERNEL_APIC_H__ diff --git a/Core/Interrupts/IntManager.cpp b/Core/Interrupts/IntManager.cpp index 7b25b39..7ac4df4 100644 --- a/Core/Interrupts/IntManager.cpp +++ b/Core/Interrupts/IntManager.cpp @@ -3,14 +3,24 @@ #if defined(__amd64__) #include "../Architecture/amd64/cpu/gdt.hpp" #include "../Architecture/amd64/cpu/idt.hpp" +#include "../Architecture/amd64/acpi.hpp" +#include "../Architecture/amd64/cpu/apic.hpp" #elif defined(__i386__) #include "../Architecture/i686/cpu/gdt.hpp" #include "../Architecture/i686/cpu/idt.hpp" #elif defined(__aarch64__) #endif +#include "../kernel.h" + namespace Interrupts { +#if defined(__amd64__) + APIC::APIC *apic = nullptr; +#elif defined(__i386__) +#elif defined(__aarch64__) +#endif + void Initialize() { #if defined(__amd64__) @@ -23,6 +33,16 @@ namespace Interrupts void Enable() { - +#if defined(__amd64__) + if (((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress != nullptr) + apic = new APIC::APIC; + else + { + error("LAPIC not found"); + // PIC + } +#elif defined(__i386__) +#elif defined(__aarch64__) +#endif } } diff --git a/Kernel.cpp b/Kernel.cpp index af478f1..b0cba88 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -16,6 +16,8 @@ SymbolResolver::Symbols *KernelSymbolTable = nullptr; Power::Power *PowerManager = nullptr; PCI::PCI *PCIManager = nullptr; +Time BootClock; + // For the Display class. Printing on first buffer. extern "C" void putchar(char c) { Display->Print(c, 0); } @@ -46,6 +48,7 @@ EXTERNC void aarch64Entry(uint64_t dtb_ptr32, uint64_t x1, uint64_t x2, uint64_t EXTERNC void Entry(BootInfo *Info) { + BootClock = ReadClock(); trace("Hello, World!"); InitializeMemoryManagement(Info); bInfo = (BootInfo *)KernelAllocator.RequestPages(TO_PAGES(sizeof(BootInfo))); @@ -54,6 +57,9 @@ EXTERNC void Entry(BootInfo *Info) Display = new Video::Display(bInfo->Framebuffer[0]); printf_("\eFFFFFF%s - %s [\e058C19%s\eFFFFFF]\n", KERNEL_NAME, KERNEL_VERSION, GIT_COMMIT_SHORT); /**************************************************************************************/ + KPrint("Time: \e8888FF%02d:%02d:%02d %02d/%02d/%02d UTC", + BootClock.Hour, BootClock.Minute, BootClock.Second, + BootClock.Day, BootClock.Month, BootClock.Year); KPrint("Initializing GDT and IDT"); Interrupts::Initialize(); KPrint("Loading kernel symbols"); @@ -64,13 +70,16 @@ EXTERNC void Entry(BootInfo *Info) PCIManager = new PCI::PCI; foreach (auto hdr in PCIManager->GetDevices()) { - KPrint("Found PCI device: %s / %s / %s / %s / %s", + KPrint("Found PCI device: \e8888FF%s \eCCCCCC/ \e8888FF%s \eCCCCCC/ \e8888FF%s \eCCCCCC/ \e8888FF%s \eCCCCCC/ \e8888FF%s", PCI::Descriptors::GetVendorName(hdr->VendorID), PCI::Descriptors::GetDeviceName(hdr->VendorID, hdr->DeviceID), PCI::Descriptors::DeviceClasses[hdr->Class], PCI::Descriptors::GetSubclassName(hdr->Class, hdr->Subclass), PCI::Descriptors::GetProgIFName(hdr->Class, hdr->Subclass, hdr->ProgIF)); } + KPrint("Enabling interrupts"); + Interrupts::Enable(); + KPrint("\e058C19######## \eE85230END \e058C19########"); while (1) CPU::Halt(); } diff --git a/include/cpu.hpp b/include/cpu.hpp index 26860b6..c45dbdb 100644 --- a/include/cpu.hpp +++ b/include/cpu.hpp @@ -132,6 +132,456 @@ namespace CPU namespace x64 { + enum CPUIDFeatures + { + CPUID_FEAT_RCX_SSE3 = 1 << 0, + CPUID_FEAT_RCX_PCLMULQDQ = 1 << 1, + CPUID_FEAT_RCX_DTES64 = 1 << 2, + CPUID_FEAT_RCX_MONITOR = 1 << 3, + CPUID_FEAT_RCX_DS_CPL = 1 << 4, + CPUID_FEAT_RCX_VMX = 1 << 5, + CPUID_FEAT_RCX_SMX = 1 << 6, + CPUID_FEAT_RCX_EST = 1 << 7, + CPUID_FEAT_RCX_TM2 = 1 << 8, + CPUID_FEAT_RCX_SSSE3 = 1 << 9, + CPUID_FEAT_RCX_CID = 1 << 10, + CPUID_FEAT_RCX_FMA = 1 << 12, + CPUID_FEAT_RCX_CX16 = 1 << 13, + CPUID_FEAT_RCX_ETPRD = 1 << 14, + CPUID_FEAT_RCX_PDCM = 1 << 15, + CPUID_FEAT_RCX_PCIDE = 1 << 17, + CPUID_FEAT_RCX_DCA = 1 << 18, + CPUID_FEAT_RCX_SSE4_1 = 1 << 19, + CPUID_FEAT_RCX_SSE4_2 = 1 << 20, + CPUID_FEAT_RCX_x2APIC = 1 << 21, + CPUID_FEAT_RCX_MOVBE = 1 << 22, + CPUID_FEAT_RCX_POPCNT = 1 << 23, + CPUID_FEAT_RCX_AES = 1 << 25, + CPUID_FEAT_RCX_XSAVE = 1 << 26, + CPUID_FEAT_RCX_OSXSAVE = 1 << 27, + CPUID_FEAT_RCX_AVX = 1 << 28, + CPUID_FEAT_RCX_F16C = 1 << 29, + CPUID_FEAT_RCX_RDRAND = 1 << 30, + + CPUID_FEAT_RDX_FPU = 1 << 0, + CPUID_FEAT_RDX_VME = 1 << 1, + CPUID_FEAT_RDX_DE = 1 << 2, + CPUID_FEAT_RDX_PSE = 1 << 3, + CPUID_FEAT_RDX_TSC = 1 << 4, + CPUID_FEAT_RDX_MSR = 1 << 5, + CPUID_FEAT_RDX_PAE = 1 << 6, + CPUID_FEAT_RDX_MCE = 1 << 7, + CPUID_FEAT_RDX_CX8 = 1 << 8, + CPUID_FEAT_RDX_APIC = 1 << 9, + CPUID_FEAT_RDX_SEP = 1 << 11, + CPUID_FEAT_RDX_MTRR = 1 << 12, + CPUID_FEAT_RDX_PGE = 1 << 13, + CPUID_FEAT_RDX_MCA = 1 << 14, + CPUID_FEAT_RDX_CMOV = 1 << 15, + CPUID_FEAT_RDX_PAT = 1 << 16, + CPUID_FEAT_RDX_PSE36 = 1 << 17, + CPUID_FEAT_RDX_PSN = 1 << 18, + CPUID_FEAT_RDX_CLF = 1 << 19, + CPUID_FEAT_RDX_DTES = 1 << 21, + CPUID_FEAT_RDX_ACPI = 1 << 22, + CPUID_FEAT_RDX_MMX = 1 << 23, + CPUID_FEAT_RDX_FXSR = 1 << 24, + CPUID_FEAT_RDX_SSE = 1 << 25, + CPUID_FEAT_RDX_SSE2 = 1 << 26, + CPUID_FEAT_RDX_SS = 1 << 27, + CPUID_FEAT_RDX_HTT = 1 << 28, + CPUID_FEAT_RDX_TM1 = 1 << 29, + CPUID_FEAT_RDX_IA64 = 1 << 30, + CPUID_FEAT_RDX_PBE = 1 << 31, + + // ? Not sure how to get it. + CPUID_FEAT_RDX_SMEP = 1 << 7, + CPUID_FEAT_RDX_UMIP = 1 << 2, + CPUID_FEAT_RDX_SYSCALL = 1 << 11, + CPUID_FEAT_XD = 1 << 20, + CPUID_FEAT_1GB_PAGE = 1 << 26, + CPUID_FEAT_RDTSCP = 1 << 27, + CPUID_FEAT_LONG_MODE = 1 << 29, + CPUID_FEAT_RDX_SMAP = (1 << 20) + }; + + enum MSRID + { + MSR_MONITOR_FILTER_SIZE = 0x6, + MSR_TIME_STAMP_COUNTER = 0x10, + MSR_PLATFORM_ID = 0x17, + MSR_APIC_BASE = 0x1B, + MSR_FEATURE_CONTROL = 0x3A, + MSR_TSC_ADJUST = 0x3B, + MSR_SPEC_CTRL = 0x48, + MSR_PRED_CMD = 0x49, + MSR_BIOS_UPDT_TRIG = 0x79, + MSR_BIOS_SIGN_ID = 0x8B, + MSR_SGXLEPUBKEYHASH0 = 0x8C, + MSR_SGXLEPUBKEYHASH1 = 0x8D, + MSR_SGXLEPUBKEYHASH2 = 0x8E, + MSR_SGXLEPUBKEYHASH3 = 0x8F, + MSR_SMM_MONITOR_CTL = 0x9B, + MSR_SMBASE = 0x9E, + MSR_PMC0 = 0xC1, + MSR_PMC1 = 0xC2, + MSR_PMC2 = 0xC3, + MSR_PMC3 = 0xC4, + MSR_PMC4 = 0xC5, + MSR_PMC5 = 0xC6, + MSR_PMC6 = 0xC7, + MSR_PMC7 = 0xC8, + MSR_UMWAIT_CONTROL = 0xE1, + MSR_MPERF = 0xE7, + MSR_APERF = 0xE8, + MSR_MTRRCAP = 0xFE, + MSR_ARCH_CAPABILITIES = 0x10A, + MSR_FLUSH_CMD = 0x10B, + MSR_SYSENTER_CS = 0x17A, + MSR_SYSENTER_ESP = 0x175, + MSR_SYSENTER_EIP = 0x176, + MSR_MCG_CAP = 0x179, + MSR_MCG_STATUS = 0x17A, + MSR_MCG_CTL = 0x17B, + MSR_PERFEVTSEL0 = 0x186, + MSR_PERFEVTSEL1 = 0x187, + MSR_PERFEVTSEL2 = 0x188, + MSR_PERFEVTSEL3 = 0x189, + MSR_PERF_STATUS = 0x198, + MSR_PERF_CTL = 0x199, + MSR_CLOCK_MODULATION = 0x19A, + MSR_THERM_INTERRUPT = 0x19B, + MSR_THERM_STATUS = 0x19C, + MSR_MISC_ENABLE = 0x1A0, + MSR_ENERGY_PERF_BIAS = 0x1B0, + MSR_PACKAGE_THERM_STATUS = 0x1B1, + MSR_PACKAGE_THERM_INTERRUPT = 0x1B2, + MSR_DEBUGCTL = 0x1D9, + MSR_SMRR_PHYSBASE = 0x1F2, + MSR_SMRR_PHYSMASK = 0x1F3, + MSR_PLATFORM_DCA_CAP = 0x1F8, + MSR_CPU_DCA_CAP = 0x1F9, + MSR_DCA_0_CAP = 0x1FA, + MSR_MTRR_PHYSBASE0 = 0x200, + MSR_MTRR_PHYSMASK0 = 0x201, + MSR_MTRR_PHYSBASE1 = 0x202, + MSR_MTRR_PHYSMASK1 = 0x203, + MSR_MTRR_PHYSBASE2 = 0x204, + MSR_MTRR_PHYSMASK2 = 0x205, + MSR_MTRR_PHYSBASE3 = 0x206, + MSR_MTRR_PHYSMASK3 = 0x207, + MSR_MTRR_PHYSBASE4 = 0x208, + MSR_MTRR_PHYSMASK4 = 0x209, + MSR_MTRR_PHYSBASE5 = 0x20A, + MSR_MTRR_PHYSMASK5 = 0x20B, + MSR_MTRR_PHYSBASE6 = 0x20C, + MSR_MTRR_PHYSMASK6 = 0x20D, + MSR_MTRR_PHYSBASE7 = 0x20E, + MSR_MTRR_PHYSMASK7 = 0x20F, + MSR_MTRR_PHYSBASE8 = 0x210, + MSR_MTRR_PHYSMASK8 = 0x211, + MSR_MTRR_PHYSBASE9 = 0x212, + MSR_MTRR_PHYSMASK9 = 0x213, + MSR_MTRR_FIX64K_00000 = 0x250, + MSR_MTRR_FIX16K_80000 = 0x258, + MSR_MTRR_FIX16K_A0000 = 0x259, + MSR_MTRR_FIX4K_C0000 = 0x268, + MSR_MTRR_FIX4K_C8000 = 0x269, + MSR_MTRR_FIX4K_D0000 = 0x26A, + MSR_MTRR_FIX4K_D8000 = 0x26B, + MSR_MTRR_FIX4K_E0000 = 0x26C, + MSR_MTRR_FIX4K_E8000 = 0x26D, + MSR_MTRR_FIX4K_F0000 = 0x26E, + MSR_MTRR_FIX4K_F8000 = 0x26F, + MSR_PAT = 0x277, + MSR_MC0_CTL2 = 0x280, + MSR_MC1_CTL2 = 0x281, + MSR_MC2_CTL2 = 0x282, + MSR_MC3_CTL2 = 0x283, + MSR_MC4_CTL2 = 0x284, + MSR_MC5_CTL2 = 0x285, + MSR_MC6_CTL2 = 0x286, + MSR_MC7_CTL2 = 0x287, + MSR_MC8_CTL2 = 0x288, + MSR_MC9_CTL2 = 0x289, + MSR_MC10_CTL2 = 0x28A, + MSR_MC11_CTL2 = 0x28B, + MSR_MC12_CTL2 = 0x28C, + MSR_MC13_CTL2 = 0x28D, + MSR_MC14_CTL2 = 0x28E, + MSR_MC15_CTL2 = 0x28F, + MSR_MC16_CTL2 = 0x290, + MSR_MC17_CTL2 = 0x291, + MSR_MC18_CTL2 = 0x292, + MSR_MC19_CTL2 = 0x293, + MSR_MC20_CTL2 = 0x294, + MSR_MC21_CTL2 = 0x295, + MSR_MC22_CTL2 = 0x296, + MSR_MC23_CTL2 = 0x297, + MSR_MC24_CTL2 = 0x298, + MSR_MC25_CTL2 = 0x299, + MSR_MC26_CTL2 = 0x29A, + MSR_MC27_CTL2 = 0x29B, + MSR_MC28_CTL2 = 0x29C, + MSR_MC29_CTL2 = 0x29D, + MSR_MC30_CTL2 = 0x29E, + MSR_MC31_CTL2 = 0x29F, + MSR_MTRR_DEF_TYPE = 0x2FF, + MSR_FIXED_CTR0 = 0x309, + MSR_FIXED_CTR1 = 0x30A, + MSR_FIXED_CTR2 = 0x30B, + MSR_PERF_CAPABILITIES = 0x345, + MSR_FIXED_CTR_CTRL = 0x38D, + MSR_PERF_GLOBAL_STATUS = 0x38E, + MSR_PERF_GLOBAL_CTRL = 0x38F, + MSR_PERF_GLOBAL_STATUS_RESET = 0x390, + MSR_PERF_GLOBAL_STATUS_SET = 0x391, + MSR_PERF_GLOBAL_INUSE = 0x392, + MSR_PEBS_ENABLE = 0x3F1, + MSR_MC0_CTL = 0x400, + MSR_MC0_STATUS = 0x401, + MSR_MC0_ADDR = 0x402, + MSR_MC0_MISC = 0x403, + MSR_MC1_CTL = 0x404, + MSR_MC1_STATUS = 0x405, + MSR_MC1_ADDR = 0x406, + MSR_MC1_MISC = 0x407, + MSR_MC2_CTL = 0x408, + MSR_MC2_STATUS = 0x409, + MSR_MC2_ADDR = 0x40A, + MSR_MC2_MISC = 0x40B, + MSR_MC3_CTL = 0x40C, + MSR_MC3_STATUS = 0x40D, + MSR_MC3_ADDR = 0x40E, + MSR_MC3_MISC = 0x40F, + MSR_MC4_CTL = 0x410, + MSR_MC4_STATUS = 0x411, + MSR_MC4_ADDR = 0x412, + MSR_MC4_MISC = 0x413, + MSR_MC5_CTL = 0x414, + MSR_MC5_STATUS = 0x415, + MSR_MC5_ADDR = 0x416, + MSR_MC5_MISC = 0x417, + MSR_MC6_CTL = 0x418, + MSR_MC6_STATUS = 0x419, + MSR_MC6_ADDR = 0x41A, + MSR_MC6_MISC = 0x41B, + MSR_MC7_CTL = 0x41C, + MSR_MC7_STATUS = 0x41D, + MSR_MC7_ADDR = 0x41E, + MSR_MC7_MISC = 0x41F, + MSR_MC8_CTL = 0x420, + MSR_MC8_STATUS = 0x421, + MSR_MC8_ADDR = 0x422, + MSR_MC8_MISC = 0x423, + MSR_MC9_CTL = 0x424, + MSR_MC9_STATUS = 0x425, + MSR_MC9_ADDR = 0x426, + MSR_MC9_MISC = 0x427, + MSR_MC10_CTL = 0x428, + MSR_MC10_STATUS = 0x429, + MSR_MC10_ADDR = 0x42A, + MSR_MC10_MISC = 0x42B, + MSR_MC11_CTL = 0x42C, + MSR_MC11_STATUS = 0x42D, + MSR_MC11_ADDR = 0x42E, + MSR_MC11_MISC = 0x42F, + MSR_MC12_CTL = 0x430, + MSR_MC12_STATUS = 0x431, + MSR_MC12_ADDR = 0x432, + MSR_MC12_MISC = 0x433, + MSR_MC13_CTL = 0x434, + MSR_MC13_STATUS = 0x435, + MSR_MC13_ADDR = 0x436, + MSR_MC13_MISC = 0x437, + MSR_MC14_CTL = 0x438, + MSR_MC14_STATUS = 0x439, + MSR_MC14_ADDR = 0x43A, + MSR_MC14_MISC = 0x43B, + MSR_MC15_CTL = 0x43C, + MSR_MC15_STATUS = 0x43D, + MSR_MC15_ADDR = 0x43E, + MSR_MC15_MISC = 0x43F, + MSR_MC16_CTL = 0x440, + MSR_MC16_STATUS = 0x441, + MSR_MC16_ADDR = 0x442, + MSR_MC16_MISC = 0x443, + MSR_MC17_CTL = 0x444, + MSR_MC17_STATUS = 0x445, + MSR_MC17_ADDR = 0x446, + MSR_MC17_MISC = 0x447, + MSR_MC18_CTL = 0x448, + MSR_MC18_STATUS = 0x449, + MSR_MC18_ADDR = 0x44A, + MSR_MC18_MISC = 0x44B, + MSR_MC19_CTL = 0x44C, + MSR_MC19_STATUS = 0x44D, + MSR_MC19_ADDR = 0x44E, + MSR_MC19_MISC = 0x44F, + MSR_MC20_CTL = 0x450, + MSR_MC20_STATUS = 0x451, + MSR_MC20_ADDR = 0x452, + MSR_MC20_MISC = 0x453, + MSR_MC21_CTL = 0x454, + MSR_MC21_STATUS = 0x455, + MSR_MC21_ADDR = 0x456, + MSR_MC21_MISC = 0x457, + MSR_MC22_CTL = 0x458, + MSR_MC22_STATUS = 0x459, + MSR_MC22_ADDR = 0x45A, + MSR_MC22_MISC = 0x45B, + MSR_MC23_CTL = 0x45C, + MSR_MC23_STATUS = 0x45D, + MSR_MC23_ADDR = 0x45E, + MSR_MC23_MISC = 0x45F, + MSR_MC24_CTL = 0x460, + MSR_MC24_STATUS = 0x461, + MSR_MC24_ADDR = 0x462, + MSR_MC24_MISC = 0x463, + MSR_MC25_CTL = 0x464, + MSR_MC25_STATUS = 0x465, + MSR_MC25_ADDR = 0x466, + MSR_MC25_MISC = 0x467, + MSR_MC26_CTL = 0x468, + MSR_MC26_STATUS = 0x469, + MSR_MC26_ADDR = 0x46A, + MSR_MC26_MISC = 0x46B, + MSR_MC27_CTL = 0x46C, + MSR_MC27_STATUS = 0x46D, + MSR_MC27_ADDR = 0x46E, + MSR_MC27_MISC = 0x46F, + MSR_MC28_CTL = 0x470, + MSR_MC28_STATUS = 0x471, + MSR_MC28_ADDR = 0x472, + MSR_MC28_MISC = 0x473, + MSR_VMX_BASIC = 0x480, + MSR_VMX_PINBASED_CTLS = 0x481, + MSR_VMX_PROCBASED_CTLS = 0x482, + MSR_VMX_EXIT_CTLS = 0x483, + MSR_VMX_ENTRY_CTLS = 0x484, + MSR_VMX_MISC = 0x485, + MSR_VMX_CR0_FIXED0 = 0x486, + MSR_VMX_CR0_FIXED1 = 0x487, + MSR_VMX_CR4_FIXED0 = 0x488, + MSR_VMX_CR4_FIXED1 = 0x489, + MSR_VMX_VMCS_ENUM = 0x48A, + MSR_VMX_PROCBASED_CTLS2 = 0x48B, + MSR_VMX_EPT_VPID_CAP = 0x48C, + MSR_VMX_TRUE_PINBASED_CTLS = 0x48D, + MSR_VMX_TRUE_PROCBASED_CTLS = 0x48E, + MSR_VMX_TRUE_EXIT_CTLS = 0x48F, + MSR_VMX_TRUE_ENTRY_CTLS = 0x490, + MSR_VMX_VMFUNC = 0x491, + MSR_A_PMC0 = 0x4C1, + MSR_A_PMC1 = 0x4C2, + MSR_A_PMC2 = 0x4C3, + MSR_A_PMC3 = 0x4C4, + MSR_A_PMC4 = 0x4C5, + MSR_A_PMC5 = 0x4C6, + MSR_A_PMC6 = 0x4C7, + MSR_A_PMC7 = 0x4C8, + MSR_MCG_EXT_CTL = 0x4D0, + MSR_SGX_SVN_STATUS = 0x500, + MSR_RTIT_OUTPUT_BASE = 0x560, + MSR_RTIT_OUTPUT_MASK_PTRS = 0x561, + MSR_RTIT_CTL = 0x570, + MSR_RTIT_STATUS = 0x571, + MSR_RTIT_CR3_MATCH = 0x572, + MSR_RTIT_ADDR0_A = 0x580, + MSR_RTIT_ADDR0_B = 0x581, + MSR_RTIT_ADDR1_A = 0x582, + MSR_RTIT_ADDR1_B = 0x583, + MSR_RTIT_ADDR2_A = 0x584, + MSR_RTIT_ADDR2_B = 0x585, + MSR_RTIT_ADDR3_A = 0x586, + MSR_RTIT_ADDR3_B = 0x587, + MSR_DS_AREA = 0x600, + MSR_TSC_DEADLINE = 0x6E0, + MSR_PM_ENABLE = 0x770, + MSR_HWP_CAPABILITIES = 0x771, + MSR_HWP_REQUEST_PKG = 0x772, + MSR_HWP_INTERRUPT = 0x773, + MSR_HWP_REQUEST = 0x774, + MSR_HWP_STATUS = 0x777, + MSR_X2APIC_APICID = 0x802, + MSR_X2APIC_VERSION = 0x803, + MSR_X2APIC_TPR = 0x808, + MSR_X2APIC_PPR = 0x80A, + MSR_X2APIC_EOI = 0x80B, + MSR_X2APIC_LDR = 0x80D, + MSR_X2APIC_SIVR = 0x80F, + MSR_X2APIC_ISR0 = 0x810, + MSR_X2APIC_ISR1 = 0x811, + MSR_X2APIC_ISR2 = 0x812, + MSR_X2APIC_ISR3 = 0x813, + MSR_X2APIC_ISR4 = 0x814, + MSR_X2APIC_ISR5 = 0x815, + MSR_X2APIC_ISR6 = 0x816, + MSR_X2APIC_ISR7 = 0x817, + MSR_X2APIC_TMR0 = 0x818, + MSR_X2APIC_TMR1 = 0x819, + MSR_X2APIC_TMR2 = 0x81A, + MSR_X2APIC_TMR3 = 0x81B, + MSR_X2APIC_TMR4 = 0x81C, + MSR_X2APIC_TMR5 = 0x81D, + MSR_X2APIC_TMR6 = 0x81E, + MSR_X2APIC_TMR7 = 0x81F, + MSR_X2APIC_IRR0 = 0x820, + MSR_X2APIC_IRR1 = 0x821, + MSR_X2APIC_IRR2 = 0x822, + MSR_X2APIC_IRR3 = 0x823, + MSR_X2APIC_IRR4 = 0x824, + MSR_X2APIC_IRR5 = 0x825, + MSR_X2APIC_IRR6 = 0x826, + MSR_X2APIC_IRR7 = 0x827, + MSR_X2APIC_ESR = 0x828, + MSR_X2APIC_LVT_CMCI = 0x82F, + MSR_X2APIC_ICR = 0x830, + MSR_X2APIC_LVT_TIMER = 0x832, + MSR_X2APIC_LVT_THERMAL = 0x833, + MSR_X2APIC_LVT_PMI = 0x834, + MSR_X2APIC_LVT_LINT0 = 0x835, + MSR_X2APIC_LVT_LINT1 = 0x836, + MSR_X2APIC_LVT_ERROR = 0x837, + MSR_X2APIC_INIT_COUNT = 0x838, + MSR_X2APIC_CUR_COUNT = 0x839, + MSR_X2APIC_DIV_CONF = 0x83E, + MSR_X2APIC_SELF_IPI = 0x83F, + MSR_DEBUG_INTERFACE = 0xC80, + MSR_L3_QOS_CFG = 0xC81, + MSR_L2_QOS_CFG = 0xC82, + MSR_QM_EVTSEL = 0xC8D, + MSR_QM_CTR = 0xC8E, + MSR_PQR_ASSOC = 0xC8F, + MSR_L3_MASK_0 = 0xC90, + MSR_L2_MASK_0 = 0xD10, + MSR_BNDCFGS = 0xD90, + MSR_XSS = 0xDA0, + MSR_PKG_HDC_CTL = 0xDB0, + MSR_PM_CTL1 = 0xDB1, + MSR_THREAD_STALL = 0xDB2, + /** @brief Extended Feature Enable Register (0xc0000080) */ + MSR_EFER = 0xC0000080, + /** @brief legacy SYSCALL (0xC0000081) */ + MSR_STAR = 0xC0000081, + /** @brief 64bit SYSCALL (0xC0000082) */ + MSR_LSTAR = 0xC0000082, + /** @brief compatibility mode SYSCALL (0xC0000083) */ + MSR_CSTAR = 0xC0000083, + /** @brief EFLAGS mask for syscall (0xC0000084) */ + MSR_SYSCALL_MASK = 0xC0000084, + /** @brief 64bit FS base (0xC0000100) */ + MSR_FS_BASE = 0xC0000100, + /** @brief 64bit GS base (0xC0000101) */ + MSR_GS_BASE = 0xC0000101, + /** @brief SwapGS GS shadow (0xC0000102) */ + MSR_SHADOW_GS_BASE = 0xC0000102, + /** @brief Auxiliary TSC (0xC0000103) */ + MSR_TSC_AUX = 0xC0000103, + MSR_CR_PAT = 0x00000277, + MSR_CR_PAT_RESET = 0x0007040600070406ULL + }; + typedef enum { DivideByZero = 0x0, @@ -548,6 +998,29 @@ namespace CPU asmv("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(Function)); +#endif + } + + static inline uint64_t rdmsr(uint32_t msr) + { + uint32_t Low, High; +#if defined(__amd64__) + asmv("rdmsr" + : "=a"(Low), "=d"(High) + : "c"(msr) + : "memory"); +#endif + return ((uint64_t)Low) | (((uint64_t)High) << 32); + } + + static inline void wrmsr(uint32_t msr, uint64_t Value) + { + uint32_t Low = Value, High = Value >> 32; +#if defined(__amd64__) + asmv("wrmsr" + : + : "c"(msr), "a"(Low), "d"(High) + : "memory"); #endif } } diff --git a/include/smp.hpp b/include/smp.hpp new file mode 100644 index 0000000..afc18b5 --- /dev/null +++ b/include/smp.hpp @@ -0,0 +1,35 @@ +#ifndef __FENNIX_KERNEL_SMP_H__ +#define __FENNIX_KERNEL_SMP_H__ + +#include + +#define CPU_DATA_CHECKSUM 0xC0FFEE + +struct CPUData +{ + /** + * @brief CPU ID. + */ + uint64_t ID; + /** + * @brief Local CPU error code. + */ + long ErrorCode; + /** + * @brief Is CPU online? + */ + bool IsActive; + /** + * @brief Architecture-specific CPU data. + */ + void *Data; + /** + * @brief Checksum. Used to verify the integrity of the data. Must be equal to CPU_DATA_CHECKSUM (0xC0FFEE). + */ + int Checksum; +} __attribute__((packed)); + +CPUData *GetCurrentCPU(); +CPUData *GetCPU(uint64_t ID); + +#endif // !__FENNIX_KERNEL_SMP_H__