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/xapic.h>
9 #include <arch/kernel/x2apic.h>
10
11 #ifdef CONFIG_XAPIC
12 #ifdef CONFIG_USE_LOGICAL_IDS
13 /* using flat cluster mode we only support 8 cores */
14 compile_assert(number_of_cores_invalid_for_logical_ids, CONFIG_MAX_NUM_NODES <= 8)
15
16 BOOT_CODE static void
init_xapic_ldr(void)17 init_xapic_ldr(void)
18 {
19 uint32_t ldr;
20
21 apic_write_reg(APIC_DEST_FORMAT, XAPIC_DFR_FLAT);
22 ldr = apic_read_reg(APIC_LOGICAL_DEST) & MASK(XAPIC_LDR_SHIFT);
23 ldr |= (BIT(getCurrentCPUIndex()) << XAPIC_LDR_SHIFT);
24 apic_write_reg(APIC_LOGICAL_DEST, ldr);
25 }
26 #endif /* CONFIG_USE_LOGICAL_IDS */
27
apic_enable(void)28 BOOT_CODE bool_t apic_enable(void)
29 {
30 apic_base_msr_t apic_base_msr;
31 apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
32
33 if (!apic_base_msr_get_enabled(apic_base_msr)) {
34 printf("APIC: Enabled bit not set\n");
35 return false;
36 }
37
38 if (x2apic_is_enabled()) {
39 printf("x2APIC enabled in BIOS but kernel does not support that\n");
40 return false;
41 }
42
43 #ifdef CONFIG_USE_LOGICAL_IDS
44 init_xapic_ldr();
45 #endif /* CONFIG_USE_LOGICAL_IDS */
46
47 return true;
48 }
49
apic_is_interrupt_pending(void)50 bool_t apic_is_interrupt_pending(void)
51 {
52 word_t i;
53
54 /* read 256-bit register: each 32-bit word is 16 byte aligned */
55 assert(int_irq_min % 32 == 0);
56 for (i = int_irq_min; i <= int_irq_max; i += 32) {
57 if (apic_read_reg(APIC_IRR_BASE + i / 2) != 0) {
58 return true;
59 }
60 }
61 return false;
62 }
63
apic_send_init_ipi(cpu_id_t cpu_id)64 BOOT_CODE void apic_send_init_ipi(cpu_id_t cpu_id)
65 {
66 apic_write_icr(
67 apic_icr2_new(
68 cpu_id /* dest */
69 ).words[0],
70 apic_icr1_new(
71 0, /* dest_shorthand */
72 1, /* trigger_mode */
73 1, /* level */
74 0, /* delivery_status */
75 0, /* dest_mode */
76 5, /* delivery_mode */
77 0 /* vector */
78 ).words[0]
79 );
80 apic_write_icr(
81 apic_icr2_new(
82 cpu_id /* dest */
83 ).words[0],
84 apic_icr1_new(
85 0, /* dest_shorthand */
86 1, /* trigger_mode */
87 0, /* level */
88 0, /* delivery_status */
89 0, /* dest_mode */
90 5, /* delivery_mode */
91 0 /* vector */
92 ).words[0]
93 );
94 }
95
apic_send_startup_ipi(cpu_id_t cpu_id,paddr_t startup_addr)96 BOOT_CODE void apic_send_startup_ipi(cpu_id_t cpu_id, paddr_t startup_addr)
97 {
98 /* check if 4K aligned */
99 assert(IS_ALIGNED(startup_addr, PAGE_BITS));
100 /* check if startup_addr < 640K */
101 assert(startup_addr < 0xa0000);
102 startup_addr >>= PAGE_BITS;
103
104 apic_write_icr(
105 apic_icr2_new(
106 cpu_id /* dest */
107 ).words[0],
108 apic_icr1_new(
109 0, /* dest_shorthand */
110 0, /* trigger_mode */
111 0, /* level */
112 0, /* delivery_status */
113 0, /* dest_mode */
114 6, /* delivery_mode */
115 startup_addr /* vector */
116 ).words[0]
117 );
118 }
119
apic_send_ipi_core(irq_t vector,cpu_id_t cpu_id)120 void apic_send_ipi_core(irq_t vector, cpu_id_t cpu_id)
121 {
122 apic_icr1_t icr1;
123 /* wait till we can send an IPI */
124 do {
125 icr1.words[0] = apic_read_reg(APIC_ICR1);
126 } while (apic_icr1_get_delivery_status(icr1));
127
128 apic_write_icr(
129 apic_icr2_new(
130 cpu_id /* dest */
131 ).words[0],
132 apic_icr1_new(
133 0, /* dest_shorthand */
134 0, /* trigger_mode */
135 0, /* level */
136 0, /* delivery_status */
137 0, /* dest_mode */
138 0, /* delivery_mode */
139 vector /* vector */
140 ).words[0]
141 );
142 }
143
apic_send_ipi_cluster(irq_t vector,word_t mda)144 void apic_send_ipi_cluster(irq_t vector, word_t mda)
145 {
146 apic_icr1_t icr1;
147 /* wait till we can send an IPI */
148 do {
149 icr1.words[0] = apic_read_reg(APIC_ICR1);
150 } while (apic_icr1_get_delivery_status(icr1));
151
152 apic_write_icr(
153 apic_icr2_new(
154 mda /* message destination address */
155 ).words[0],
156 apic_icr1_new(
157 0, /* dest_shorthand */
158 0, /* trigger_mode */
159 0, /* level */
160 0, /* delivery_status */
161 1, /* dest_mode */
162 0, /* delivery_mode */
163 vector /* vector */
164 ).words[0]
165 );
166 }
167 #endif /* CONFIG_XAPIC */
168