Skip to content

Commit 057aef4

Browse files
arch/x86_64: add support for xAPIC
Add support for legacy xAPIC alongside x2APIC. This way we can run nuttx x86_64 on qemu without the --enable-kvm option Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
1 parent 76b90e0 commit 057aef4

10 files changed

Lines changed: 214 additions & 120 deletions

File tree

arch/x86_64/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ if ARCH_CHIP_INTEL64_QEMU
143143
source "arch/x86_64/src/qemu/Kconfig"
144144
endif
145145

146+
config ARCH_X86_64_X2APIC
147+
bool "Use X2APIC mode"
148+
default y
149+
---help---
150+
Use X2APIC mode to access local APIC. By default, this option is enabled
151+
because every new CPU supports X2APIC. The main reason for this option is
152+
to support QEMU without the `--enable-kvm` argument.
153+
146154
config ARCH_MULTIBOOT1
147155
bool "Enable ELF32/Multiboot1"
148156
default n

arch/x86_64/include/intel64/arch.h

Lines changed: 82 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -276,69 +276,88 @@
276276
# define MSR_IA32_APIC_X2APIC 0x400
277277
# define MSR_IA32_APIC_BSP 0x100
278278

279-
#define MSR_X2APIC_ID 0x802
280-
#define MSR_X2APIC_VER 0x803
281-
#define MSR_X2APIC_TPR 0x808
282-
#define MSR_X2APIC_PPR 0x80a
283-
#define MSR_X2APIC_EOI 0x80b
284-
#define MSR_X2APIC_LDR 0x80d
285-
286-
#define MSR_X2APIC_SPIV 0x80f
287-
# define MSR_X2APIC_SPIV_EN 0x100
288-
289-
#define MSR_X2APIC_ISR0 0x810
290-
#define MSR_X2APIC_ISR1 0x811
291-
#define MSR_X2APIC_ISR2 0x812
292-
#define MSR_X2APIC_ISR3 0x813
293-
#define MSR_X2APIC_ISR4 0x814
294-
#define MSR_X2APIC_ISR5 0x815
295-
#define MSR_X2APIC_ISR6 0x816
296-
#define MSR_X2APIC_ISR7 0x817
297-
298-
#define MSR_X2APIC_TMR0 0x818
299-
#define MSR_X2APIC_TMR1 0x819
300-
#define MSR_X2APIC_TMR2 0x81a
301-
#define MSR_X2APIC_TMR3 0x81b
302-
#define MSR_X2APIC_TMR4 0x81c
303-
#define MSR_X2APIC_TMR5 0x81d
304-
#define MSR_X2APIC_TMR6 0x81e
305-
#define MSR_X2APIC_TMR7 0x81f
306-
307-
#define MSR_X2APIC_IRR0 0x820
308-
#define MSR_X2APIC_IRR1 0x821
309-
#define MSR_X2APIC_IRR2 0x822
310-
#define MSR_X2APIC_IRR3 0x823
311-
#define MSR_X2APIC_IRR4 0x824
312-
#define MSR_X2APIC_IRR5 0x825
313-
#define MSR_X2APIC_IRR6 0x826
314-
#define MSR_X2APIC_IRR7 0x827
315-
316-
#define MSR_X2APIC_ESR 0x828
317-
#define MSR_X2APIC_ICR 0x830
318-
# define MSR_X2APIC_ICR_INIT 0x00000500 /* INIT/RESET */
319-
# define MSR_X2APIC_ICR_STARTUP 0x00000600 /* Startup IPI */
320-
# define MSR_X2APIC_ICR_DELIVS 0x00001000 /* Delivery status */
321-
# define MSR_X2APIC_ICR_ASSERT 0x00004000 /* Assert interrupt (vs deassert) */
322-
# define MSR_X2APIC_ICR_DEASSERT 0x00000000
323-
# define MSR_X2APIC_ICR_LEVEL 0x00008000 /* Level triggered */
324-
# define MSR_X2APIC_ICR_BCAST 0x00080000 /* Send to all APICs, including self. */
325-
# define MSR_X2APIC_ICR_OTHERS 0x000c0000 /* Send to all APICs, excluding self. */
326-
# define MSR_X2APIC_ICR_BUSY 0x00001000
327-
# define MSR_X2APIC_ICR_FIXED 0x00000000
328-
# define MSR_X2APIC_DESTINATION(d) ((d) << 32)
329-
#define MSR_X2APIC_LVTT 0x832
330-
# define MSR_X2APIC_LVTT_X1 0x0000000B /* divide counts by 1 */
331-
# define MSR_X2APIC_LVTT_PERIODIC 0x00020000 /* Periodic */
332-
# define MSR_X2APIC_LVTT_TSC_DEADLINE 0x00040000 /* Enable TSC DEADLINE One-shot timer */
333-
#define MSR_X2APIC_LVTTHER 0x833
334-
#define MSR_X2APIC_LVTPMR 0x834
335-
#define MSR_X2APIC_LINT0 0x835
336-
#define MSR_X2APIC_LINT1 0x836
337-
#define MSR_X2APIC_LERR 0x837
338-
# define MSR_X2APIC_MASKED 0x00010000 /* Interrupt masked */
339-
#define MSR_X2APIC_TMICT 0x838
340-
#define MSR_X2APIC_TMCCT 0x839
341-
#define MSR_X2APIC_TDCR 0x83e
279+
#define MSR_IA32_PM_ENABLE 0x770 /* Enable/disable HWP (R/W) */
280+
#define MSR_IA32_HWP_CAPABILITIES 0x771 /* HWP Performance Range Enumeration (R/O) */
281+
#define MSR_IA32_HWP_REQUEST_PKG 0x772 /* Power Management Control Hints for All Logical Processors in a Package (R/W) */
282+
#define MSR_IA32_HWP_INTERRUPT 0x773 /* Control HWP Native Interrupts (R/W) */
283+
#define MSR_IA32_HWP_REQUEST 0x774 /* Power Management Control Hints to a Logical Processor (R/W) */
284+
#define MSR_IA32_PECI_HWP_REQUEST_INFO 0x775
285+
#define MSR_IA32_HWP_CTL 0x776
286+
#define MSR_IA32_HWP_STATUS 0x777
287+
288+
/* APIC */
289+
290+
#define APIC_BASE 0xfee00000
291+
292+
#define APIC_ID 0x0020
293+
#define APIC_VER 0x0030
294+
#define APIC_TPR 0x0080
295+
#define APIC_PPR 0x00a0
296+
#define APIC_EOI 0x00b0
297+
# define APIC_EOI_ACK 0
298+
#define APIC_LDR 0x00d0
299+
#define APIC_SPIV 0x00f0
300+
# define APIC_SPIV_EN 0x100
301+
302+
#define APIC_ISR0 0x0100
303+
#define APIC_ISR1 0x0110
304+
#define APIC_ISR2 0x0120
305+
#define APIC_ISR3 0x0130
306+
#define APIC_ISR4 0x0140
307+
#define APIC_ISR5 0x0150
308+
#define APIC_ISR6 0x0160
309+
#define APIC_ISR7 0x0170
310+
311+
#define APIC_TMR0 0x0180
312+
#define APIC_TMR1 0x0190
313+
#define APIC_TMR2 0x01a0
314+
#define APIC_TMR3 0x01b0
315+
#define APIC_TMR4 0x01c0
316+
#define APIC_TMR5 0x01d0
317+
#define APIC_TMR6 0x01e0
318+
#define APIC_TMR7 0x01f0
319+
320+
#define APIC_IRR0 0x0200
321+
#define APIC_IRR1 0x0210
322+
#define APIC_IRR2 0x0220
323+
#define APIC_IRR3 0x0230
324+
#define APIC_IRR4 0x0240
325+
#define APIC_IRR5 0x0250
326+
#define APIC_IRR6 0x0260
327+
#define APIC_IRR7 0x0270
328+
329+
#define APIC_ESR 0x0280
330+
#define APIC_ICR 0x0300
331+
# define APIC_ICR_INIT 0x00000500 /* INIT/RESET */
332+
# define APIC_ICR_STARTUP 0x00000600 /* Startup IPI */
333+
# define APIC_ICR_DELIVS 0x00001000 /* Delivery status */
334+
# define APIC_ICR_ASSERT 0x00004000 /* Assert interrupt (vs deassert) */
335+
# define APIC_ICR_DEASSERT 0x00000000
336+
# define APIC_ICR_LEVEL 0x00008000 /* Level triggered */
337+
# define APIC_ICR_BCAST 0x00080000 /* Send to all APICs, including self. */
338+
# define APIC_ICR_OTHERS 0x000c0000 /* Send to all APICs, excluding self. */
339+
# define APIC_ICR_BUSY 0x00001000
340+
# define APIC_ICR_FIXED 0x00000000
341+
# define X2APIC_DESTINATION(d) ((d) << 32)
342+
# define APIC_DESTINATION(d) ((d) << 24)
343+
#define APIC_ICR_HIGH 0x0310
344+
#define APIC_LVTT 0x0320
345+
# define APIC_LVTT_X1 0x0000000B /* divide counts by 1 */
346+
# define APIC_LVTT_PERIODIC 0x00020000 /* Periodic */
347+
# define APIC_LVTT_TSC_DEADLINE 0x00040000 /* Enable TSC DEADLINE One-shot timer */
348+
#define APIC_LVTTHER 0x0330
349+
#define APIC_LVTPMR 0x0340
350+
#define APIC_LINT0 0x0350
351+
#define APIC_LINT1 0x0360
352+
#define APIC_LERR 0x0370
353+
# define APIC_MASKED 0x00010000 /* Interrupt masked */
354+
#define APIC_TMICT 0x0380
355+
#define APIC_TMCCT 0x0390
356+
#define APIC_TDCR 0x03e0
357+
358+
/* MSR */
359+
360+
#define MSR_X2APIC_BASE 0x800
342361
#define MSR_IA32_XSS 0xda0
343362

344363
/* IOAPIC related Definitions */

arch/x86_64/include/intel64/irq.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,9 +862,36 @@ static inline_function void up_irq_restore(irqstate_t flags)
862862
}
863863
}
864864

865+
static inline_function void apic_write(unsigned int offset,
866+
unsigned long val)
867+
{
868+
#ifdef CONFIG_ARCH_X86_64_X2APIC
869+
write_msr((offset >> 4) + MSR_X2APIC_BASE, val);
870+
#else
871+
uintptr_t addr = APIC_BASE + offset;
872+
873+
/* xAPIC access must be 32-bit aligned */
874+
875+
*((FAR volatile uint32_t *)addr) = val;
876+
#endif
877+
}
878+
879+
static inline_function unsigned long apic_read(unsigned int offset)
880+
{
881+
#ifdef CONFIG_ARCH_X86_64_X2APIC
882+
return read_msr((offset >> 4) + MSR_X2APIC_BASE);
883+
#else
884+
uintptr_t addr = APIC_BASE + offset;
885+
886+
/* xAPIC access must be 32-bit aligned */
887+
888+
return *((FAR volatile uint32_t *)addr);
889+
#endif
890+
}
891+
865892
static inline_function unsigned int up_apic_cpu_id(void)
866893
{
867-
return read_msr(MSR_X2APIC_ID);
894+
return apic_read(APIC_ID);
868895
}
869896

870897
/****************************************************************************

arch/x86_64/src/common/x86_64_internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ void x86_64_stack_color(void *stackbase, size_t nbytes);
308308
int x86_64_tlb_handler(int irq, void *c, void *arg);
309309
void x86_64_tlb_shootdown(void);
310310

311+
/* Defined in intel64_irq.c */
312+
313+
void x86_64_icr_write(uint8_t cpu, uint32_t delivery);
314+
311315
#endif /* __ASSEMBLY__ */
312316

313317
#endif /* __ARCH_X86_64_SRC_COMMON_UP_INTERNAL_H */

arch/x86_64/src/intel64/intel64_check_capability.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,11 @@ void x86_64_check_and_enable_capability(void)
9898
require |= X86_64_CPUID_01_SSE42;
9999
#endif
100100

101+
#ifdef CONFIG_ARCH_X86_64_X2APIC
101102
/* Check x2APIC availability */
102103

103104
require |= X86_64_CPUID_01_X2APIC;
105+
#endif
104106

105107
/* Check timer availability */
106108

arch/x86_64/src/intel64/intel64_cpustart.c

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,17 @@ extern uint64_t get_tsc_adjust(void);
7171

7272
static int x86_64_ap_startup(int cpu)
7373
{
74-
uint64_t dest = 0;
75-
uint64_t vect = 0;
76-
uint64_t regval = 0;
74+
uint64_t vect = 0;
7775

7876
sinfo("cpu=%d\n", cpu);
7977

80-
/* Get destination - must be LOAPIC id */
81-
82-
dest = MSR_X2APIC_DESTINATION((uint64_t)x86_64_cpu_to_loapic(cpu));
83-
8478
/* Get the AP trampoline from a fixed address */
8579

8680
vect = (uint32_t)((uintptr_t)&__ap_entry) >> 12;
8781

8882
/* Send an INIT IPI to the CPU */
8983

90-
regval = MSR_X2APIC_ICR_INIT | MSR_X2APIC_ICR_ASSERT
91-
| MSR_X2APIC_ICR_LEVEL | dest;
92-
write_msr(MSR_X2APIC_ICR, regval);
84+
x86_64_icr_write(cpu, APIC_ICR_INIT | APIC_ICR_ASSERT | APIC_ICR_LEVEL);
9385

9486
/* Wait for 10 ms */
9587

@@ -98,8 +90,7 @@ static int x86_64_ap_startup(int cpu)
9890

9991
/* Send an STARTUP IPI to the CPU */
10092

101-
regval = MSR_X2APIC_ICR_STARTUP | dest | vect;
102-
write_msr(MSR_X2APIC_ICR, regval);
93+
x86_64_icr_write(cpu, APIC_ICR_STARTUP | vect);
10394

10495
/* Wait for AP ready */
10596

arch/x86_64/src/intel64/intel64_handlers.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@
4141
#include "x86_64_internal.h"
4242
#include "sched/sched.h"
4343

44-
/****************************************************************************
45-
* Pre-processor Definitions
46-
****************************************************************************/
47-
48-
#define X2APIC_EOI 0x80b
49-
50-
#define APIC_EOI_ACK 0
51-
5244
/****************************************************************************
5345
* Private Functions
5446
****************************************************************************/
@@ -164,7 +156,7 @@ uint64_t *irq_handler(uint64_t *regs, uint64_t irq_no)
164156

165157
/* Send an EOI (end of interrupt) signal to the APIC */
166158

167-
write_msr(X2APIC_EOI, APIC_EOI_ACK);
159+
apic_write(APIC_EOI, APIC_EOI_ACK);
168160
board_autoled_off(LED_INIRQ);
169161
return ret;
170162
#endif

0 commit comments

Comments
 (0)