1 /*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <config.h>
8 #include <arch/kernel/x2apic.h>
9
x2apic_is_enabled(void)10 BOOT_CODE bool_t x2apic_is_enabled(void)
11 {
12 apic_base_msr_t apic_base_msr;
13 apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
14
15 if ((x86_cpuid_ecx(1, 0) & BIT(21)) &&
16 apic_base_msr_get_enabled(apic_base_msr) &&
17 apic_base_msr_get_x2apic(apic_base_msr)) {
18 return true;
19 }
20 return false;
21 }
22
23 #ifdef CONFIG_X2APIC
apic_enable(void)24 BOOT_CODE bool_t apic_enable(void)
25 {
26 apic_base_msr_t apic_base_msr;
27 apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
28
29 if (!apic_base_msr_get_enabled(apic_base_msr)) {
30 printf("APIC: Enabled bit not set\n");
31 return false;
32 }
33
34 if (x86_cpuid_ecx(1, 0) & BIT(21)) {
35 apic_base_msr = apic_base_msr_set_x2apic(apic_base_msr, 1);
36 x86_wrmsr(IA32_APIC_BASE_MSR, apic_base_msr.words[0]);
37 } else {
38 printf("APIC: x2APIC is not supported on this machine\n");
39 return false;
40 }
41
42 return true;
43 }
44
apic_is_interrupt_pending(void)45 bool_t apic_is_interrupt_pending(void)
46 {
47 word_t i;
48
49 assert(int_irq_min % 32 == 0);
50 for (i = int_irq_min; i <= int_irq_max; i += 32) {
51 if (apic_read_reg(APIC_IRR_BASE + ((i / 32) - 1)) != 0) {
52 return true;
53 }
54 }
55 return false;
56 }
57
apic_send_init_ipi(cpu_id_t cpu_id)58 BOOT_CODE void apic_send_init_ipi(cpu_id_t cpu_id)
59 {
60 apic_write_icr(
61 x2apic_icr2_new(
62 cpu_id /* dest */
63 ).words[0],
64 x2apic_icr1_new(
65 0, /* dest_shorthand */
66 1, /* trigger_mode */
67 1, /* level */
68 0, /* dest_mode */
69 5, /* delivery_mode */
70 0 /* vector */
71 ).words[0]
72 );
73 apic_write_icr(
74 apic_icr2_new(
75 cpu_id /* dest */
76 ).words[0],
77 x2apic_icr1_new(
78 0, /* dest_shorthand */
79 1, /* trigger_mode */
80 0, /* level */
81 0, /* dest_mode */
82 5, /* delivery_mode */
83 0 /* vector */
84 ).words[0]
85 );
86 }
87
apic_send_startup_ipi(cpu_id_t cpu_id,paddr_t startup_addr)88 BOOT_CODE void apic_send_startup_ipi(cpu_id_t cpu_id, paddr_t startup_addr)
89 {
90 /* check if 4K aligned */
91 assert(IS_ALIGNED(startup_addr, PAGE_BITS));
92 /* check if startup_addr < 640K */
93 assert(startup_addr < 0xa0000);
94 startup_addr >>= PAGE_BITS;
95
96 apic_write_icr(
97 x2apic_icr2_new(
98 cpu_id /* dest */
99 ).words[0],
100 x2apic_icr1_new(
101 0, /* dest_shorthand */
102 0, /* trigger_mode */
103 0, /* level */
104 0, /* dest_mode */
105 6, /* delivery_mode */
106 startup_addr /* vector */
107 ).words[0]
108 );
109 }
110
apic_send_ipi_core(irq_t vector,cpu_id_t cpu_id)111 void apic_send_ipi_core(irq_t vector, cpu_id_t cpu_id)
112 {
113 apic_write_icr(
114 x2apic_icr2_new(
115 cpu_id /* dest */
116 ).words[0],
117 x2apic_icr1_new(
118 0, /* dest_shorthand */
119 0, /* trigger_mode */
120 0, /* level */
121 0, /* dest_mode */
122 0, /* delivery_mode */
123 vector /* vector */
124 ).words[0]
125 );
126 }
127
apic_send_ipi_cluster(irq_t vector,word_t mda)128 void apic_send_ipi_cluster(irq_t vector, word_t mda)
129 {
130 apic_write_icr(
131 x2apic_icr2_new(
132 mda /* message destination address */
133 ).words[0],
134 x2apic_icr1_new(
135 0, /* dest_shorthand */
136 0, /* trigger_mode */
137 0, /* level */
138 1, /* dest_mode */
139 0, /* delivery_mode */
140 vector /* vector */
141 ).words[0]
142 );
143 }
144 #endif /* CONFIG_X2APIC */
145