1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org)
// Licensed under the Apache License, Version 2.0 (see LICENSE file)
// Official repository: https://github.com/nekernel-org/nekernel
#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 <NeKit/KernelPanic.h>
#include <modules/ACPI/ACPIFactoryInterface.h>
#include <modules/CoreGfx/TextGfx.h>
///////////////////////////////////////////////////////////////////////////////////////
/// @note: _hal_switch_context is internal.
/// @brief The **HAL** namespace.
///////////////////////////////////////////////////////////////////////////////////////
namespace Kernel::HAL {
struct HAL_APIC_MADT;
struct HAL_HARDWARE_THREAD;
struct HAL_HARDWARE_THREAD final {
StackFramePtr mFramePtr;
ProcessID mThreadID{0};
};
EXTERN_C Void sched_jump_to_task(StackFramePtr stack_frame);
STATIC HAL_APIC_MADT* kSMPBlock = nullptr;
STATIC Bool kSMPAware = false;
STATIC Int64 kSMPCount = 0;
EXTERN_C UIntPtr kApicBaseAddress;
STATIC Int32 kSMPInterrupt = 0;
STATIC UInt64 kAPICLocales[kMaxAPInsideSched] = {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
UInt32 Flags; // Madt flags
UInt8 List[1]; // Records List
};
/// @brief Local APIC Descriptor Table.
struct LAPIC final {
UInt8 Type;
UInt8 Length;
UInt8 ProcessorID;
UInt8 APICID;
UInt32 Flags;
};
///////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************/
/// @brief Send end IPI for CPU.
/// @param apic_id
/// @param vector
/// @param target
/// @return
/***********************************************************************************/
EXTERN_C 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, APIC_ICR_LOW) & 0x1000) {
NE_UNUSED(0);
}
}
/***********************************************************************************/
/// @brief Get current stack frame for a thread.
/// @param thrdid The thread ID.
/***********************************************************************************/
EXTERN_C HAL::StackFramePtr mp_get_current_task(ThreadID thrdid) {
if (thrdid > kSMPCount) return nullptr;
return kHWThread[thrdid].mFramePtr;
}
/***********************************************************************************/
/// @brief Register current stack frame for a thread.
/// @param stack_frame The current stack frame.
/// @param thrdid The thread ID.
/***********************************************************************************/
EXTERN_C BOOL mp_register_task(HAL::StackFramePtr stack_frame, ThreadID thrdid) {
if (!stack_frame) return NO;
if (!kSMPAware) {
sched_jump_to_task(stack_frame);
return YES;
}
if (thrdid > kSMPCount) return NO;
kHWThread[thrdid].mThreadID = thrdid;
kHWThread[thrdid].mFramePtr = stack_frame;
hal_send_ipi_msg(thrdid, kAPICLocales[thrdid], kSMPInterrupt + 32);
return YES;
}
/***********************************************************************************/
/// @brief Is the current config SMP aware?
/// @return True if YES, False if not.
/***********************************************************************************/
Bool mp_is_smp(Void) {
return kSMPAware;
}
/***********************************************************************************/
/// @brief Fetch and enable SMP scheduler.
/// @param vendor_ptr SMP containing structure.
/***********************************************************************************/
Void mp_init_cores(VoidPtr vendor_ptr) {
if (!vendor_ptr) return;
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();
kSMPBlock = reinterpret_cast<HAL_APIC_MADT*>(kRawMADT);
kSMPAware = NO;
if (kSMPBlock) {
kSMPInterrupt = 0;
kSMPCount = 0;
UInt32 lo = 0U, hi = 0U;
hal_get_msr(APIC_BASE_MSR, &lo, &hi);
UInt64 apic_base = ((UInt64) hi << 32) | lo;
apic_base |= APIC_BASE_MSR_ENABLE; // Enable APIC.
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*>(kSMPBlock->List);
volatile UInt8* end_ptr = ((UInt8*) kSMPBlock) + kSMPBlock->Length;
while (entry_ptr < end_ptr) {
UInt8 type = *entry_ptr;
UInt8 length = *(entry_ptr + 1);
if (type == 0 && length == sizeof(struct LAPIC)) {
volatile LAPIC* entry_struct = (volatile LAPIC*) entry_ptr;
if (entry_struct->Flags & 0x1) {
kAPICLocales[kSMPCount] = entry_struct->ProcessorID;
kHWThread[kSMPCount].mThreadID = kAPICLocales[kSMPCount];
++kSMPCount;
kout << "AP: kind: LAPIC: ON.\r";
} else {
kout << "AP: kind: LAPIC: OFF.\r";
}
} else {
kout << "AP: kind: UNKNOWN: OFF.\r";
}
entry_ptr += length;
}
}
}
} // namespace Kernel::HAL
///////////////////////////////////////////////////////////////////////////////////////
|