Skip to content

Commit 49d308c

Browse files
ValidationKit/bootsectors/bs3-apic-1: Allow testing x2APIC mode as well
svn:sync-xref-src-repo-rev: r174573
1 parent 3ebc2fe commit 49d308c

2 files changed

Lines changed: 135 additions & 46 deletions

File tree

src/VBox/ValidationKit/bootsectors/bs3-apic-1-32.c32

Lines changed: 128 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $Id: bs3-apic-1-32.c32 114735 2026-07-21 07:31:36Z alexander.eichner@oracle.com $ */
1+
/* $Id: bs3-apic-1-32.c32 114736 2026-07-21 10:54:49Z alexander.eichner@oracle.com $ */
22
/** @file
33
* BS3Kit - bs3-apic-1, 32-bit C code.
44
*/
@@ -47,18 +47,23 @@
4747
#define CPUS_MAX 32
4848
#define CPU_STACK_SIZE _4K
4949

50-
#define APIC_VECTOR 0x70
50+
#define APIC_VECTOR 0x70
51+
#define APIC_X2APIC_VECTOR 0x71
5152

5253
typedef struct APICCPU
5354
{
5455
/** The stack for this CPU. */
55-
uint8_t abStack[CPU_STACK_SIZE];
56+
uint8_t abStack[CPU_STACK_SIZE];
57+
/** The MMIO base for the APIC when in xAPIC mode. */
58+
uint32_t BS3_FAR volatile * pau32Apic;
5659
/** The assigned CPU ID, equals APIC ID. */
57-
uint32_t idCpu;
60+
uint32_t idCpu;
5861
/** Flag whether the CPU should busy wait for the next interrupt. */
59-
bool fBusyWait;
62+
bool fBusyWait;
63+
/** Flag whether the APIC is in x2Apic mode. */
64+
bool fX2Apic;
6065
/** Padding. */
61-
bool afAlignment[11];
66+
bool afAlignment[6];
6267
} APICCPU;
6368
typedef APICCPU *PAPICCPU;
6469
AssertCompileSizeAlignment(APICCPU, 16);
@@ -123,21 +128,24 @@ static void bs3ApicTestFailedF(const char BS3_FAR *pszFormat, ...)
123128
}
124129

125130

126-
static uint32_t BS3_FAR volatile * const bs3ApicGetMmioBase(PAPICCPU *ppApicCpu)
131+
static PAPICCPU bs3ApicGetCpu(void)
127132
{
128133
uint64_t uApicBase;
129134

130135
uApicBase = ASMRdMsr(MSR_IA32_APICBASE);
131136
if (uApicBase & MSR_IA32_APICBASE_EN)
132137
{
133-
uint8_t BS3_FAR volatile * const pabApic = (uint8_t BS3_FAR volatile *)((uintptr_t)uApicBase & X86_PAGE_4K_BASE_MASK);
134-
uint32_t BS3_FAR volatile * const pau32Apic = (uint32_t BS3_FAR volatile *)pabApic;
135-
uint32_t const idApic = pau32Apic[XAPIC_OFF_ID / sizeof(uint32_t)] >> 24;
136-
137-
if (ppApicCpu)
138-
*ppApicCpu = &g_paCpus[idApic];
138+
uint32_t idApic = UINT32_MAX;
139+
if (uApicBase & MSR_IA32_APICBASE_EXTD)
140+
idApic = (uint32_t)ASMRdMsr(MSR_IA32_X2APIC_ID);
141+
else
142+
{
143+
uint8_t BS3_FAR volatile * const pabApic = (uint8_t BS3_FAR volatile *)((uintptr_t)uApicBase & X86_PAGE_4K_BASE_MASK);
144+
uint32_t BS3_FAR volatile * const pau32Apic = (uint32_t BS3_FAR volatile *)pabApic;
145+
idApic = pau32Apic[XAPIC_OFF_ID / sizeof(uint32_t)] >> 24;
146+
}
139147

140-
return pau32Apic;
148+
return &g_paCpus[idApic];
141149
}
142150

143151
return NULL;
@@ -146,11 +154,32 @@ static uint32_t BS3_FAR volatile * const bs3ApicGetMmioBase(PAPICCPU *ppApicCpu)
146154

147155
BS3_DECL_NEAR_CALLBACK(void) BS3_CMN_NM(bs3ApicIpiHandler)(PBS3TRAPFRAME pTrapFrame)
148156
{
149-
PAPICCPU pCpu = NULL;
150-
uint32_t BS3_FAR volatile * const pau32Apic = bs3ApicGetMmioBase(&pCpu);
151-
if (pau32Apic)
157+
PAPICCPU pCpu = bs3ApicGetCpu();
158+
if (pCpu)
159+
{
160+
if (pCpu->fX2Apic)
161+
ASMWrMsr(MSR_IA32_X2APIC_EOI, 0);
162+
else
163+
pCpu->pau32Apic[XAPIC_OFF_EOI / sizeof(uint32_t)] = 0;
164+
ASMAtomicIncU32(&g_cCpusResponded);
165+
}
166+
else
167+
bs3ApicTestFailedF("APIC not enabled!");
168+
169+
RT_NOREF(pTrapFrame);
170+
}
171+
172+
173+
BS3_DECL_NEAR_CALLBACK(void) BS3_CMN_NM(bs3ApicX2ApicSwitch)(PBS3TRAPFRAME pTrapFrame)
174+
{
175+
PAPICCPU pCpu = bs3ApicGetCpu();
176+
if (pCpu)
152177
{
153-
pau32Apic[XAPIC_OFF_EOI / sizeof(uint32_t)] = 0;
178+
uint64_t uApicBase = ASMRdMsr(MSR_IA32_APICBASE);
179+
ASMWrMsr(MSR_IA32_APICBASE, uApicBase | MSR_IA32_APICBASE_EXTD);
180+
pCpu->fX2Apic = true;
181+
ASMWrMsr(MSR_IA32_X2APIC_SVR, XAPIC_SVR_SOFTWARE_ENABLE);
182+
ASMWrMsr(MSR_IA32_X2APIC_EOI, 0);
154183
ASMAtomicIncU32(&g_cCpusResponded);
155184
}
156185
else
@@ -175,7 +204,8 @@ BS3_DECL(uint32_t) bs3ApicApStartup_pe32(void)
175204
uint32_t const idApic = pau32Apic[XAPIC_OFF_ID / sizeof(uint32_t)] >> 24;
176205
PAPICCPU pApicCpu = &g_paCpus[idApic];
177206

178-
pApicCpu->idCpu = idApic;
207+
pApicCpu->idCpu = idApic;
208+
pApicCpu->pau32Apic = pau32Apic;
179209

180210
pau32Apic[XAPIC_OFF_SVR / sizeof(uint32_t)] = XAPIC_SVR_SOFTWARE_ENABLE;
181211
ASMAtomicIncU32(&g_cCpus);
@@ -188,18 +218,34 @@ BS3_DECL(uint32_t) bs3ApicApStartup_pe32(void)
188218
}
189219

190220

191-
DECLINLINE(void) apicWriteIcr(uint32_t BS3_FAR volatile * const pau32Apic, uint8_t bDestination,
221+
DECLINLINE(void) apicWriteIcr(PAPICCPU pApicCpu, uint8_t bDestination,
192222
XAPICDESTSHORTHAND enmShorthand, XAPICDELIVERYMODE enmDeliveryMode,
193223
XAPICDESTMODE enmMode, XAPICTRIGGERMODE enmTriggerMode,
194224
XAPICLEVEL enmLevel, uint8_t bVector)
195225
{
196-
pau32Apic[XAPIC_OFF_ICR_HI / sizeof(uint32_t)] = (uint32_t)bDestination << 24;
197-
pau32Apic[XAPIC_OFF_ICR_LO / sizeof(uint32_t)] = ((uint32_t)enmShorthand << 18)
198-
| ((uint32_t)enmMode == XAPICDESTMODE_LOGICAL ? RT_BIT_32(11) : 0)
199-
| ((uint32_t)enmDeliveryMode << 8)
200-
| (enmTriggerMode == XAPICTRIGGERMODE_LEVEL ? RT_BIT_32(15) : 0)
201-
| (enmLevel == XAPICINITLEVEL_ASSERT ? RT_BIT_32(14) : 0)
202-
| bVector;
226+
if (pApicCpu->fX2Apic)
227+
{
228+
uint64_t const uWr = ((uint64_t)bDestination) << 32
229+
| ((uint64_t)enmShorthand << 18)
230+
| ((uint64_t)enmMode == XAPICDESTMODE_LOGICAL ? RT_BIT_64(11) : 0)
231+
| ((uint64_t)enmDeliveryMode << 8)
232+
| (enmTriggerMode == XAPICTRIGGERMODE_LEVEL ? RT_BIT_64(15) : 0)
233+
| (enmLevel == XAPICINITLEVEL_ASSERT ? RT_BIT_64(14) : 0)
234+
| bVector;
235+
ASMWrMsr(MSR_IA32_X2APIC_ICR, uWr);
236+
}
237+
else
238+
{
239+
uint32_t BS3_FAR volatile * const pau32Apic = pApicCpu->pau32Apic;
240+
241+
pau32Apic[XAPIC_OFF_ICR_HI / sizeof(uint32_t)] = (uint32_t)bDestination << 24;
242+
pau32Apic[XAPIC_OFF_ICR_LO / sizeof(uint32_t)] = ((uint32_t)enmShorthand << 18)
243+
| ((uint32_t)enmMode == XAPICDESTMODE_LOGICAL ? RT_BIT_32(11) : 0)
244+
| ((uint32_t)enmDeliveryMode << 8)
245+
| (enmTriggerMode == XAPICTRIGGERMODE_LEVEL ? RT_BIT_32(15) : 0)
246+
| (enmLevel == XAPICINITLEVEL_ASSERT ? RT_BIT_32(14) : 0)
247+
| bVector;
248+
}
203249
}
204250

205251

@@ -209,8 +255,14 @@ static bool bs3ApicStartAllAps(uint32_t BS3_FAR volatile * const pau32Apic)
209255
if (g_paCpus)
210256
{
211257
/* Allocate a single 4K page and make sure it is aligned on a page boundary and the physical address fits into the 8-bit vector. */
258+
PAPICCPU pApicCpu = &g_paCpus[0];
212259
void BS3_FAR *pv = Bs3MemAllocZ(BS3MEMKIND_REAL, _4K);
213260
uintptr_t const uPtr = (uintptr_t)pv;
261+
262+
pApicCpu->idCpu = 0;
263+
pApicCpu->fX2Apic = false;
264+
pApicCpu->pau32Apic = pau32Apic;
265+
214266
if ( !(uPtr & X86_PAGE_OFFSET_MASK)
215267
&& (uPtr >> X86_PAGE_SHIFT) < UINT8_MAX)
216268
{
@@ -219,28 +271,29 @@ static bool bs3ApicStartAllAps(uint32_t BS3_FAR volatile * const pau32Apic)
219271
Bs3MemCpy(pv, bs3ApicApTrampoline, (uintptr_t)bs3ApicApTrampoline_EndProc - (uintptr_t)bs3ApicApTrampoline);
220272
g_AddrApInitStack = uPtr + _4K; /* Use the unused top of the trampoline code for the initial stack. */
221273

222-
Bs3TrapSetHandler(APIC_VECTOR, bs3ApicIpiHandler_c32);
274+
Bs3TrapSetHandler(APIC_VECTOR, bs3ApicIpiHandler_c32);
275+
Bs3TrapSetHandler(APIC_X2APIC_VECTOR, bs3ApicX2ApicSwitch_c32);
223276

224277
/* Enable xAPIC. */
225278
pau32Apic[XAPIC_OFF_SVR / sizeof(uint32_t)] = XAPIC_SVR_SOFTWARE_ENABLE;
226279

227280
/* Send INIT to all APs. */
228-
apicWriteIcr(pau32Apic, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_INIT,
281+
apicWriteIcr(pApicCpu, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_INIT,
229282
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_ASSERT, 0);
230283
bs3ApicBusyWait(10 * 1000);
231284

232285
/* Send INIT de-assert to all APs. */
233-
apicWriteIcr(pau32Apic, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_INIT,
286+
apicWriteIcr(pApicCpu, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_INIT,
234287
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_DEASSERT, 0);
235288
bs3ApicBusyWait(10 * 1000);
236289

237290
/* Send SIPI to APs. */
238-
apicWriteIcr(pau32Apic, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_STARTUP,
291+
apicWriteIcr(pApicCpu, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_STARTUP,
239292
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_ASSERT, bVector);
240293
bs3ApicBusyWait(200);
241294

242295
/* Send SIPI to APs. */
243-
apicWriteIcr(pau32Apic, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_STARTUP,
296+
apicWriteIcr(pApicCpu, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_STARTUP,
244297
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_ASSERT, bVector);
245298
/** @todo This assumes that the CPUs start in that time frame,
246299
* which might not be the case for IEM and heavy instruction logging enabled.
@@ -262,20 +315,56 @@ static bool bs3ApicStartAllAps(uint32_t BS3_FAR volatile * const pau32Apic)
262315
}
263316

264317

318+
static void bs3ApicRunTests(PAPICCPU pApicCpu)
319+
{
320+
if (g_cCpus)
321+
{
322+
Bs3TestSubSub("Pinging all APs");
323+
ASMAtomicWriteU32(&g_cCpusResponded, 0);
324+
apicWriteIcr(pApicCpu, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_FIXED,
325+
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_ASSERT, APIC_VECTOR);
326+
327+
while (ASMAtomicReadU32(&g_cCpusResponded) < g_cCpus)
328+
ASMNopPause();
329+
}
330+
}
331+
265332
static void ProtModeApicTestsAp(uint32_t BS3_FAR volatile * const pau32Apic)
266333
{
267334
Bs3TestSub("Starting APs");
268335
if (bs3ApicStartAllAps(pau32Apic))
269336
{
270-
if (g_cCpus)
337+
PAPICCPU pApicCpu = &g_paCpus[0];
338+
339+
Bs3TestSub("xAPIC mode");
340+
bs3ApicRunTests(pApicCpu);
341+
342+
/* Check for x2APIC. */
343+
if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
271344
{
272-
Bs3TestSub("Pinging all APs");
273-
ASMAtomicWriteU32(&g_cCpusResponded, 0);
274-
apicWriteIcr(pau32Apic, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_FIXED,
275-
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_ASSERT, APIC_VECTOR);
345+
uint32_t const uEcx = ASMCpuId_ECX(1 /*uOperator*/);
346+
if (uEcx & X86_CPUID_FEATURE_ECX_X2APIC)
347+
{
348+
uint64_t uApicBase = ASMRdMsr(MSR_IA32_APICBASE);
276349

277-
while (ASMAtomicReadU32(&g_cCpusResponded) < g_cCpus)
278-
ASMNopPause();
350+
/* Switch all APs to x2APIC mode before doing it. */
351+
ASMAtomicWriteU32(&g_cCpusResponded, 0);
352+
apicWriteIcr(pApicCpu, 0, XAPICDESTSHORTHAND_ALL_EXCL_SELF, XAPICDELIVERYMODE_FIXED,
353+
XAPICDESTMODE_PHYSICAL, XAPICTRIGGERMODE_EDGE, XAPICINITLEVEL_ASSERT, APIC_X2APIC_VECTOR);
354+
355+
ASMWrMsr(MSR_IA32_APICBASE, uApicBase | MSR_IA32_APICBASE_EXTD);
356+
ASMWrMsr(MSR_IA32_X2APIC_SVR, XAPIC_SVR_SOFTWARE_ENABLE);
357+
pApicCpu->fX2Apic = true;
358+
359+
Bs3TestSub("x2APIC mode");
360+
361+
while (ASMAtomicReadU32(&g_cCpusResponded) < g_cCpus)
362+
ASMNopPause();
363+
364+
bs3ApicRunTests(pApicCpu);
365+
}
366+
else
367+
bs3ApicTestPrintf("Skipping x2APIC tests as CPU doesn't support it\n");
279368
}
280369
}
281370
}

src/VBox/ValidationKit/bootsectors/bs3-apic-1-asm.asm

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; $Id: bs3-apic-1-asm.asm 114735 2026-07-21 07:31:36Z alexander.eichner@oracle.com $
1+
; $Id: bs3-apic-1-asm.asm 114736 2026-07-21 10:54:49Z alexander.eichner@oracle.com $
22
;; @file
33
; BS3Kit - bs3-apic-1
44
;
@@ -72,15 +72,15 @@ BS3_GLOBAL_LOCAL_LABEL .ap_thirty_two_bit
7272
mov ds, ax
7373

7474
BS3_GLOBAL_LOCAL_LABEL .ap_lck_busy
75-
mov al, 0
76-
mov bl, 1
75+
mov al, 0
76+
mov bl, 1
7777
lock cmpxchg [BS3_DATA16_WRT(g_fApLock)], bl
7878
jne .ap_lck_busy
7979

8080
;
8181
; Setup the initial stack for the AP
8282
;
83-
mov esp, dword [BS3_DATA16_WRT(g_AddrApInitStack)]
83+
mov esp, dword [BS3_DATA16_WRT(g_AddrApInitStack)]
8484

8585
mov ax, BS3_SEL_R0_SS32
8686
mov ss, ax
@@ -103,13 +103,13 @@ BS3_GLOBAL_LOCAL_LABEL .ap_lck_busy
103103
;
104104
; Set the final stack top returned from the previous call.
105105
;
106-
mov esp, eax
106+
mov esp, eax
107107

108108
;
109109
; Unlock the AP lock so other APs can continue.
110110
;
111-
mov al, 0
112-
xchg [BS3_DATA16_WRT(g_fApLock)], al
111+
mov al, 0
112+
xchg [BS3_DATA16_WRT(g_fApLock)], al
113113

114114
.hlt_loop:
115115
; Loop for interrupts

0 commit comments

Comments
 (0)