1/**
2 * \file
3 * \brief Interrupt management (Local and IOAPICs) and routing
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2011, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <arch/aarch64/hw_records_arch.h>
16#include <stdio.h>
17#include <barrelfish/barrelfish.h>
18#include <barrelfish/cpu_arch.h>
19#include <acpi.h>
20#include <mm/mm.h>
21
22#include <skb/skb.h>
23#include <octopus/getset.h>
24#include <trace/trace.h>
25
26#include "acpi_debug.h"
27#include "acpi_shared.h"
28
29
30int init_all_interrupt_sources(void)
31{
32    ACPI_STATUS         as;
33    ACPI_TABLE_MADT     *madt;
34    ACPI_TABLE_HEADER   *ath;
35
36    static coreid_t barrelfish_id_counter = 1;
37
38    // Get the ACPI APIC table (the MADT)
39    as = AcpiGetTable("APIC", 1, (ACPI_TABLE_HEADER **)&ath);
40
41    if(ACPI_FAILURE(as)) {
42        ACPI_DEBUG("No MADT found in ACPI! Cannot initialize I/O APICs.\n");
43        return -1;
44    }
45    else {
46        madt = (ACPI_TABLE_MADT*)ath;
47    }
48
49    ACPI_DEBUG("MADT Revision: %u, Size=%u, OEM=%s\n", madt->Header.Revision,
50               madt->Header.Length, madt->Header.OemId);
51
52    //uint8_t revision = madt->Header.Revision;
53
54    // Walk all subtables (after the main table entries)
55    void *p = (void *)madt + sizeof(ACPI_TABLE_MADT);
56    while(p < (void *)madt + madt->Header.Length) {
57        ACPI_SUBTABLE_HEADER *sh = (ACPI_SUBTABLE_HEADER *)p;
58
59        uint8_t length = sh->Length;
60
61        switch(sh->Type) {
62        case ACPI_MADT_TYPE_LOCAL_APIC:
63            {
64                debug_printf("WARNING LOCAL APIC found on non x86\n");
65            }
66            break;
67
68        case ACPI_MADT_TYPE_IO_APIC:
69            {
70                debug_printf("WARNING IO APIC found on non x86\n");
71            }
72            break;
73
74        case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
75            {
76                debug_printf("WARNING INTERRUPT_OVERRIDE found on non x86\n");
77            }
78            break;
79
80        case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
81            debug_printf("WARNING LOCAL_APIC_NMI found on non x86\n");
82            break;
83        case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
84            {
85            ACPI_MADT_GENERIC_INTERRUPT *gi = (ACPI_MADT_GENERIC_INTERRUPT *)sh;
86
87            /*
88             * ACPI Spec 6.1 - 5.2.12.14 GIC CPU Interface (GICC) Structure
89             *
90             * CPU Interface Number
91             * GIC's CPU Interface Number. In GICv1/v2 implementations, this
92             * value matches the bit index of the associated processor in the GIC
93             * distributor's GICD_ITARGETSR register.
94             * For GICv3/4 implementations this field must be provided by the
95             * platform, if compatibility mode is supported.
96             * If it is not supported by the implementation, then this field must be
97             * zero
98             *
99             * UID
100             * The OS associates this GICC Structure with a processor device
101             * object in the namespace when the _UID child object of the
102             * processor device evaluates to a numeric value that matches the
103             * numeric value in this field.
104             *
105             * Parking Address
106             * The 64-bit physical address of the processor's Parking Protocol
107             * mailbox
108             *
109             * ParkingVersion
110             * Version of the ARM-Processor Parking Protocol implemented. See
111             * http://uefi.org/acpi. The document link is listed under
112             * "Multiprocessor Startup for ARM Platforms"
113             * For systems that support PSCI exclusively and do not support the
114             * parking protocol, this field must be set to 0
115             *
116             * BaseAddress
117             * On GICv1/v2 systems and GICv3/4 systems in GICv2 compatibility
118             * mode, this field holds the 64-bit physical address at which the
119             * processor can access this GIC CPU Interface. If provided here, the
120             * "Local Interrupt Controller Address" field in the MADT must be
121             * ignored by the OSPM.
122             *
123             * GICV
124             * Address of the GIC virtual CPU interface registers. If the platform
125             * is not presenting a GICv2 with virtualization extensions this field
126             * can be 0.
127             *
128             * GICH
129             * Address of the GIC virtual interface control block registers. If the
130             * platform is not presenting a GICv2 with virtualization extensions
131             * this field can be 0.
132             *
133             * On systems supporting GICv3 and above, this field holds the 64-bit
134             * physical address of the associated Redistributor. If all of the GIC
135             * Redistributors are in the always-on power domain, GICR structures
136             * should be used to describe the Redistributors instead, and this field
137             * must be set to 0.
138             *
139             * MPIDR
140             * This fields follows the MPIDR formatting of ARM architecture.
141             * If the implements ARMv7 architecure then the format must be:
142             *  Bits [63:24] Must be zero
143             *  Bits [23:16] Aff2 : Match Aff2 of target processor MPIDR
144             *  Bits [15:8] Aff1 : Match Aff1 of target processor MPIDR
145             *  Bits [7:0] Aff0 : Match Aff0 of target processor MPIDR
146             *
147             * For platforms implementing ARMv8 the format must be:
148             *  Bits [63:40] Must be zero
149             *  Bits [39:32] Aff3 : Match Aff3 of target processor MPIDR
150             *  Bits [31:24] Must be zero
151             *  Bits [23:16] Aff2 : Match Aff2 of target processor MPIDR
152             *  Bits [15:8] Aff1 : Match Aff1 of target processor MPIDR
153             *  Bits [7:0] Aff0 : Match Aff0 of target processor MPIDR
154             */
155
156/*
157            printf("Found GENERIC_INTERRUPT: BaseAddress=0x%016"
158                       PRIx64
159                       ", ParkingVersion=0x%" PRIu32
160                       ", ParkedAddress=0x%016" PRIx64
161                       ", GicvBaseAddress=0x%016" PRIx64
162                       ", GichBaseAddress=0x%016" PRIx64
163                       ", GicrBaseAddress=0x%016" PRIx64
164                       ", CpuInterfaceNumber=%" PRIu32 ", Uid=%" PRIu32
165                       ", ArmMpidr =%" PRIu64 "\n",
166                       gi->BaseAddress, gi->ParkingVersion, gi->ParkedAddress, gi->GicvBaseAddress, gi->GichBaseAddress,
167                       gi->GicrBaseAddress, gi->CpuInterfaceNumber, gi->Uid, gi->ArmMpidr);
168
169            */
170
171            coreid_t barrelfish_id;
172            if (my_hw_id == gi->Uid) {
173                barrelfish_id = 0; // BSP core is 0
174            }
175            else {
176                barrelfish_id = barrelfish_id_counter++;
177            }
178
179            /* TODO: figure out which facts you need */
180            skb_add_fact("generic_interrupt(%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%d,%d).",
181                         gi->BaseAddress, gi->GicvBaseAddress, gi->GichBaseAddress,
182                         gi->ParkedAddress, gi->CpuInterfaceNumber, gi->Uid);
183
184            if (gi->ParkingVersion) {
185                /* parking */
186                skb_add_fact("boot_driver_entry(%"PRIu64",%s).", gi->ArmMpidr,
187                             "armBootParking");
188            } else {
189                /* psci */
190                skb_add_fact("boot_driver_entry(%"PRIu64",%s).", gi->ArmMpidr,
191                                             "armBootPSCI");
192            }
193
194            errval_t err = oct_set(HW_PROCESSOR_ARMV8_RECORD_FORMAT,
195                                   barrelfish_id,
196                                   gi->Flags & ACPI_MADT_ENABLED,
197                                   barrelfish_id,
198                                   gi->ArmMpidr,
199                                   CURRENT_CPU_TYPE,
200                                   gi->CpuInterfaceNumber,
201                                   gi->Uid,
202                                   gi->Flags,
203                                   gi->ParkingVersion,
204                                   gi->PerformanceInterrupt,
205                                   gi->ParkedAddress,
206                                   gi->BaseAddress,
207                                   gi->GicvBaseAddress,
208                                   gi->GichBaseAddress,
209                                   gi->VgicInterrupt,
210                                   gi->GicrBaseAddress,
211                                   gi->ArmMpidr);
212            if (err_is_fail(err)) {
213                USER_PANIC_ERR(err, "failed to set record");
214            }
215            }
216            break;
217        case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
218            {
219            ACPI_MADT_GENERIC_DISTRIBUTOR *gd = (ACPI_MADT_GENERIC_DISTRIBUTOR *)sh;
220            debug_printf("Found GENERIC DISTRIBUTOR: BaseAddress=0x%016"
221                                   PRIx64 ", GicId=%" PRIu32 ", Version=%" PRIu8
222                                   ", GlobalIrqBase=%" PRIu32 "\n", gd->BaseAddress,
223                                   gd->GicId , gd->Version, gd->GlobalIrqBase);
224            skb_add_fact("generic_distributor(%"PRIu64",%d,%d,%d).",
225                         gd->BaseAddress, gd->GicId, gd->GlobalIrqBase, gd->Version);
226            }
227
228
229
230            break;
231        case ACPI_MADT_TYPE_GENERIC_MSI_FRAME:
232            {
233            ACPI_MADT_GENERIC_MSI_FRAME *msi = (ACPI_MADT_GENERIC_MSI_FRAME *)sh;
234            ACPI_DEBUG("Found local APIC GENERIC MSI FRAME: BaseAddress=0x%016"
235                       PRIx64 ", MsiFrameId=%" PRIu32 "\n", msi->BaseAddress,
236                       msi->MsiFrameId);
237            skb_add_fact("generic_msi_frame(%"PRIu64",%d,%d,%d,%d).",
238                         msi->BaseAddress, msi->MsiFrameId, msi->SpiBase,
239                         msi->SpiBase, msi->Flags);
240            }
241            break;
242        case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR:
243        {
244            ACPI_MADT_GENERIC_REDISTRIBUTOR *grd = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)sh;
245            debug_printf("Found GENERIC REDISTRIBUTOR: BaseAddress=0x%016"
246                        PRIx64 ", Length=%" PRIu32 "\n", grd->BaseAddress,
247                        grd->Length);
248            skb_add_fact("generic_redistributor(%"PRIu64",%d).",
249                         grd->BaseAddress, grd->Length);
250        }
251            break;
252        case ACPI_MADT_TYPE_GENERIC_TRANSLATOR:
253        {
254            ACPI_MADT_GENERIC_TRANSLATOR *gt = (ACPI_MADT_GENERIC_TRANSLATOR *)sh;
255            ACPI_DEBUG("Found local APIC GENERIC TRANSLATOR: TranslationId=%"
256                        PRIu32 ", BaseAddress=0x%016" PRIx64 "\n", gt->TranslationId,
257                        gt->BaseAddress);
258            skb_add_fact("generic_translator(%"PRIu64",%d).",
259                         gt->BaseAddress, gt->TranslationId);
260        }
261            break;
262        default:
263            ACPI_DEBUG("Unknown subtable type %d\n", sh->Type);
264            break;
265        }
266        assert(length);
267        p += length;
268    }
269
270
271#if 0
272    /* XXX: Quirk hack for QEMU
273     * There is no override for the timer interrupt, although it appears as IRQ2.
274     */
275    if (strncmp(madt->Header.OemId, "QEMU", 4) == 0
276        && interrupt_overrides[0] == 0) {
277
278    }
279#endif
280
281    ACPI_DEBUG("DONE: MADT Element %p / %p\n", p, (void *)madt + madt->Header.Length);
282
283    return 0;
284}
285
286errval_t enable_and_route_interrupt(int gsi, coreid_t dest, int vector)
287{
288    USER_PANIC("NYI!");
289    return SYS_ERR_OK;
290}
291
292
293errval_t acpi_interrupts_arch_setup(void)
294{
295    return SYS_ERR_OK;
296}
297