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