summaryrefslogtreecommitdiffhomepage
path: root/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-05-29 10:51:53 +0200
committerGitHub <noreply@github.com>2025-05-29 10:51:53 +0200
commit5c0bb7ee7b1b0fee02cc179fb21f4c57a61d6c2d (patch)
treecb17577bcdc9714c97a84ce417a075117097f146 /dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
parentd608230b1350b064ceb01e6572519b108f6139b0 (diff)
parent3167f59dbb401d6a79b1524537e04218baf49ee3 (diff)
Merge pull request #32 from nekernel-org/dev
0.0.2e3
Diffstat (limited to 'dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc')
-rw-r--r--dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc246
1 files changed, 117 insertions, 129 deletions
diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
index dd9a36ed..3e10d577 100644
--- a/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
+++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc
@@ -4,27 +4,34 @@
------------------------------------------- */
+#define APIC_MAG "APIC"
+
+#define APIC_ICR_LOW 0x300
+#define APIC_ICR_HIGH 0x310
+#define APIC_SIPI_VEC 0x00500
+#define APIC_EIPI_VEC 0x00400
+
+#define LAPIC_REG_TIMER_LVT 0x320
+#define LAPIC_REG_TIMER_INITCNT 0x380
+#define LAPIC_REG_TIMER_CURRCNT 0x390
+#define LAPIC_REG_TIMER_DIV 0x3E0
+#define LAPIC_REG_ENABLE 0x80
+#define LAPIC_REG_SPURIOUS 0xF0
+
+#define APIC_BASE_MSR 0x1B
+#define APIC_BASE_MSR_BSP 0x100
+#define APIC_BASE_MSR_ENABLE 0x800
+
#include <ArchKit/ArchKit.h>
#include <HALKit/AMD64/Processor.h>
#include <KernelKit/BinaryMutex.h>
#include <KernelKit/HardwareThreadScheduler.h>
#include <KernelKit/ProcessScheduler.h>
#include <KernelKit/Timer.h>
-#include <NewKit/KernelPanic.h>
+#include <NeKit/KernelPanic.h>
#include <modules/ACPI/ACPIFactoryInterface.h>
#include <modules/CoreGfx/TextGfx.h>
-#define kAPIC_Signature "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
///////////////////////////////////////////////////////////////////////////////////////
@@ -39,83 +46,39 @@ struct HAL_HARDWARE_THREAD;
struct HAL_HARDWARE_THREAD final {
HAL::StackFramePtr mFramePtr;
- ProcessID mProcessID{0};
- UInt8 mCoreID{0};
+ ProcessID mThreadID{0};
};
+EXTERN_C Void sched_jump_to_task(HAL::StackFramePtr stack_frame);
+
STATIC HAL_APIC_MADT* kMADTBlock = nullptr;
STATIC Bool kSMPAware = false;
STATIC Int64 kSMPCount = 0;
-STATIC UIntPtr kApicBaseAddress = 0UL;
+EXTERN_C UIntPtr kApicBaseAddress;
+
+STATIC Int32 kSMPInterrupt = 0;
+STATIC UInt64 kAPICLocales[kMaxAPInsideSched] = {0};
+STATIC VoidPtr kRawMADT = nullptr;
-STATIC Int32 kSMPInterrupt = 0;
-STATIC UInt64 kAPICLocales[kSchedProcessLimitPerTeam] = {0};
-STATIC VoidPtr kRawMADT = nullptr;
+STATIC HAL_HARDWARE_THREAD kHWThread[kSchedProcessLimitPerTeam] = {{}};
/// @brief Multiple APIC Descriptor Table.
struct HAL_APIC_MADT final SDT_OBJECT {
UInt32 Address; // Madt address
- UInt8 Flags; // Madt flags
-
- struct {
- UInt8 Type;
- UInt8 Len;
-
- union APIC {
- struct IOAPIC {
- UInt8 IoID;
- UInt8 Zero;
- UInt32 IoAddress;
- UInt32 GISBase;
- } IOAPIC;
-
- struct LAPIC_NMI {
- UInt8 Source;
- UInt8 IRQSource;
- UInt32 GSI;
- UInt16 Flags;
- } LApicNMI;
-
- struct LAPIC {
- UInt8 ProcessorID;
- UInt16 Flags;
- UInt8 LINT;
- } LAPIC;
-
- struct LAPIC_OVERRIDE {
- UInt16 Reserved;
- UInt64 Address;
- } LApicOverride;
-
- struct LAPIC_X2 {
- UInt16 Reserved;
- UInt32 x2APICID;
- UInt32 Flags;
- UInt32 AcpiID;
- } LocalApicX2;
- } Apic;
- } List[1]; // Records List
+ UInt32 Flags; // Madt flags
+ UInt8 List[1]; // 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) {
- Kernel::ke_dma_write<UInt32>(target, kAPIC_ICR_High, apic_id << 24);
- Kernel::ke_dma_write<UInt32>(target, kAPIC_ICR_Low, 0x00000500 | 0x00004000 | 0x00000000);
+struct LAPIC final {
+ UInt8 Type;
+ UInt8 Length;
+ UInt8 ProcessorID;
+ UInt8 APICID;
+ UInt32 Flags;
+};
- while (Kernel::ke_dma_read<UInt32>(target, kAPIC_ICR_Low) & 0x1000) {
- ;
- }
-}
+///////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************/
/// @brief Send end IPI for CPU.
@@ -124,36 +87,40 @@ Void hal_send_start_ipi(UInt32 target, UInt32 apic_id) {
/// @param target
/// @return
/***********************************************************************************/
-Void hal_send_sipi(UInt32 target, UInt32 apic_id, UInt8 vector) {
- Kernel::ke_dma_write<UInt32>(target, kAPIC_ICR_High, apic_id << 24);
- Kernel::ke_dma_write<UInt32>(target, kAPIC_ICR_Low,
- 0x00000600 | 0x00004000 | 0x00000000 | vector);
+Void hal_send_ipi_msg(UInt32 target, UInt32 apic_id, UInt8 vector) {
+ Kernel::ke_dma_write<UInt32>(target, APIC_ICR_HIGH, apic_id << 24);
+ Kernel::ke_dma_write<UInt32>(target, APIC_ICR_LOW, 0x00000600 | 0x00004000 | 0x00000000 | vector);
- while (Kernel::ke_dma_read<UInt32>(target, kAPIC_ICR_Low) & 0x1000) {
+ while (Kernel::ke_dma_read<UInt32>(target, APIC_ICR_LOW) & 0x1000) {
NE_UNUSED(0);
}
}
-STATIC HAL_HARDWARE_THREAD kHWThread[kSchedProcessLimitPerTeam] = {{}};
-
-EXTERN_C HAL::StackFramePtr mp_get_current_context(Int64 pid) {
- const auto process_index = pid % kSchedProcessLimitPerTeam;
+/***********************************************************************************/
+/// @brief Get current stack frame for a thread.
+/// @param thrdid The thread ID.
+/***********************************************************************************/
- return kHWThread[process_index].mFramePtr;
+EXTERN_C HAL::StackFramePtr mp_get_current_task(ThreadID thrdid) {
+ if (thrdid > kSMPCount) return nullptr;
+ return kHWThread[thrdid].mFramePtr;
}
-EXTERN_C BOOL mp_register_process(HAL::StackFramePtr stack_frame, ProcessID pid) {
- MUST_PASS(stack_frame);
+/***********************************************************************************/
+/// @brief Register current stack frame for a thread.
+/// @param stack_frame The current stack frame.
+/// @param thrdid The thread ID.
+/***********************************************************************************/
- const auto process_index = pid % kSchedProcessLimitPerTeam;
+EXTERN_C BOOL mp_register_task(HAL::StackFramePtr stack_frame, ThreadID thrdid) {
+ if (thrdid > kSMPCount) return NO;
+ if (!stack_frame) return NO;
- kHWThread[process_index].mFramePtr = stack_frame;
- kHWThread[process_index].mProcessID = pid;
+ kHWThread[thrdid].mFramePtr = stack_frame;
- kHWThread[process_index].mCoreID = kAPICLocales[0];
+ HardwareThreadScheduler::The()[thrdid].Leak()->Busy(NO);
- hal_send_sipi(kApicBaseAddress, kHWThread[process_index].mCoreID,
- (UInt8) (((UIntPtr) stack_frame->BP) >> 12));
+ sched_jump_to_task(kHWThread[thrdid].mFramePtr);
return YES;
}
@@ -162,24 +129,16 @@ EXTERN_C BOOL mp_register_process(HAL::StackFramePtr stack_frame, ProcessID pid)
/// @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_init_cores(VoidPtr vendor_ptr) noexcept {
if (!vendor_ptr) return;
@@ -188,51 +147,80 @@ Void mp_init_cores(VoidPtr vendor_ptr) noexcept {
return;
}
- auto hw_and_pow_int = PowerFactoryInterface(vendor_ptr);
- kRawMADT = hw_and_pow_int.Find(kAPIC_Signature).Leak().Leak();
+ PowerFactoryInterface hw_and_pow_int{vendor_ptr};
+ auto pwr = hw_and_pow_int.Find(APIC_MAG);
+
+ if (pwr.HasError()) {
+ kSMPAware = NO;
+ return;
+ }
+
+ kRawMADT = pwr.Leak().Leak();
kMADTBlock = reinterpret_cast<HAL_APIC_MADT*>(kRawMADT);
kSMPAware = NO;
if (kMADTBlock) {
- SizeT index = 1;
-
kSMPInterrupt = 0;
kSMPCount = 0;
- kout << "SMP: Starting APs...\r";
+ UInt32 lo = 0U, hi = 0U;
- kApicBaseAddress = kMADTBlock->Address;
+ hal_get_msr(APIC_BASE_MSR, &lo, &hi);
- while (Yes) {
- /// @note Anything bigger than x2APIC type doesn't exist.
- if (kMADTBlock->List[index].Type > 9 || kSMPCount > kSchedProcessLimitPerTeam) break;
+ UInt64 apic_base = ((UInt64) hi << 32) | lo;
- switch (kMADTBlock->List[index].Type) {
- case 0x00: {
- if (kMADTBlock->List[kSMPCount].Apic.LAPIC.ProcessorID < 1) break;
+ apic_base |= APIC_BASE_MSR_ENABLE; // Enable APIC.
- kAPICLocales[kSMPCount] = kMADTBlock->List[kSMPCount].Apic.LAPIC.ProcessorID;
- (Void)(kout << "SMP: APIC ID: " << number(kAPICLocales[kSMPCount]) << kendl);
+ lo = apic_base & 0xFFFFFFFF;
+ hi = apic_base >> 32;
+ hal_set_msr(APIC_BASE_MSR, lo, hi);
+
+ kApicBaseAddress = apic_base & 0xFFFFF000;
+
+ LAPICDmaWrapper controller{(VoidPtr) kApicBaseAddress};
+
+ controller.Write(LAPIC_REG_ENABLE, 0);
+ controller.Write(LAPIC_REG_SPURIOUS, 0x1FF); // Enable bit, spurious interrupt vector register.
+ controller.Write(LAPIC_REG_TIMER_DIV, 0b0011);
+ controller.Write(LAPIC_REG_TIMER_LVT, 0x20 | (1 << 17));
+ controller.Write(LAPIC_REG_TIMER_INITCNT, 1000000);
+
+ volatile UInt8* entry_ptr = reinterpret_cast<volatile UInt8*>(kMADTBlock->List);
+ volatile UInt8* end_ptr = ((UInt8*) kMADTBlock) + kMADTBlock->Length;
+
+ while (entry_ptr < end_ptr) {
+ UInt8 type = *entry_ptr;
+ UInt8 length = *(entry_ptr + 1);
+
+ // Avoid infinite loop on bad APIC tables.
+ if (length < 2) break;
+
+ if (type == 0) {
+ volatile LAPIC* entry_struct = (volatile LAPIC*) entry_ptr;
+
+ if (entry_struct->Flags & 0x1) {
+ kAPICLocales[kSMPCount] = entry_struct->ProcessorID;
+ kHWThread[kSMPCount].mThreadID = kAPICLocales[kSMPCount];
+
++kSMPCount;
- break;
+
+ kout << "Kind: LAPIC: ON\r";
+
+ // 0x7c00, as recommended by the Intel SDM.
+ hal_send_ipi_msg(kApicBaseAddress, entry_struct->ProcessorID, 0x7c);
+ } else {
+ kout << "Kind: LAPIC: OFF\r";
}
- default:
- break;
+ } else {
+ kout << "Kind: UNKNOWN\r";
}
- ++index;
+ entry_ptr += length;
}
- (Void)(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.
+ kSMPAware = kSMPCount > 1;
}
}
} // namespace Kernel::HAL