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
10BOOT_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
24BOOT_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
45bool_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
58BOOT_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
88BOOT_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
111void 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
128void 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