1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma pack(push,1)
14
15#define ACPI_APIC_LOCAL            0x00
16#define ACPI_APIC_IOAPIC           0x01
17#define ACPI_APIC_ISO              0x02
18#define ACPI_APIC_NMI              0x03
19#define ACPI_APIC_LOCAL_NMI        0x04
20#define ACPI_APIC_LOCAL_AO         0x05
21#define ACPI_APIC_IOSAPIC          0x06
22#define ACPI_APIC_SAPIC            0x07
23#define ACPI_APIC_PINT_SRC         0x08
24#define ACPI_APIC_LOCAL_X2APIC     0x09
25#define ACPI_APIC_LOCAL_X2APIC_NMI 0x0A
26#define ACPI_APIC_GIC              0x0B
27#define ACPI_APIC_GICD             0x0C
28
29/* interrupt control structure header */
30typedef struct acpi_madt_ics_hdr {
31    uint8_t type;
32    uint8_t length;
33} acpi_madt_ics_hdr_t;
34
35/* Processor local APIC (0)*/
36typedef struct acpi_madt_local_apic {
37    acpi_madt_ics_hdr_t header;
38    uint8_t             processor_id;
39    uint8_t             apic_id;
40    uint32_t            flags;
41} acpi_madt_local_apic_t;
42
43/* IO APIC structre (1)*/
44typedef struct acpi_madt_ioapic {
45    acpi_madt_ics_hdr_t header;
46    uint8_t             ioapic_id;
47    uint8_t             res; /* 0 */
48    uint32_t             address;
49    uint32_t            gs_interrupt_base;
50} acpi_madt_ioapic_t;
51
52/* Interrupt Source Override structure (2)*/
53typedef struct acpi_madt_override {
54    acpi_madt_ics_hdr_t header;
55    uint8_t             bus;
56    uint8_t             src;
57    uint32_t            gs_interrupt;
58    uint16_t            mps_inti_flags;
59} acpi_madt_override_t;
60
61/* NMI source structure (3)*/
62typedef struct acpi_madt_nmi {
63    acpi_madt_ics_hdr_t header;
64    uint16_t            flags;
65    uint32_t            gs_interrupt;
66} acpi_madt_nmi_t;
67
68/* Local APIC NMI structure (4)*/
69typedef struct acpi_madt_locnmi {
70    acpi_madt_ics_hdr_t header;
71    uint8_t             processor_id;
72    uint16_t            flags;
73    uint8_t             local_apic_lint;
74} acpi_madt_locnmi_t;
75
76/* Local APIC address override structure (5) */
77typedef struct acpi_madt_locoverride {
78    acpi_madt_ics_hdr_t header;
79    uint8_t             res[2];
80    uint64_t             local_apic_address;
81} acpi_madt_locoverride_t;
82
83/* IO SAPIC structure (6)*/
84typedef struct acpi_madt_sapic {
85    acpi_madt_ics_hdr_t header;
86    uint8_t             ioapic_id;
87    uint8_t             res;
88    uint32_t            gs_interrupt_base;
89    uint64_t             iosapic_address;
90} acpi_madt_sapic_t;
91
92/* Processor Local SAPIC structure (7)*/
93typedef struct acpi_madt_locsapic {
94    acpi_madt_ics_hdr_t header;
95    uint8_t             processor_id;
96    uint8_t             locsapic_id;
97    uint8_t             locsapic_eid;
98    uint8_t             res[3];
99    uint32_t            flags;
100    uint32_t            processor_uid;
101    /* \0 terminated string */
102    char                processor_uid_str[];
103} acpi_madt_locsapic_t;
104
105/* Platform interrupt source (8)*/
106typedef struct acpi_madt_platformis {
107    acpi_madt_ics_hdr_t header;
108    uint16_t            flags;
109    uint8_t             int_type;
110    uint8_t             processor_id;
111    uint8_t             processor_eid;
112    uint8_t             iosapic_vector;
113    uint32_t            gs_interrupt;
114    uint32_t            platform_int_src_flags;
115} acpi_madt_platformis_t;
116
117/* Processor local x2APIC structure (9)*/
118typedef struct acpi_madt_locx2apic {
119    acpi_madt_ics_hdr_t header;
120    uint8_t             res[2]; /* 0 */
121    uint32_t            local_x2apic_id;
122    uint32_t            flags;
123    uint32_t            processor_uid;
124} acpi_madt_locx2apic;
125
126/* Local x2 APIC NMI structure (A) */
127typedef struct acpi_madt_locx2apicnmi {
128    acpi_madt_ics_hdr_t header;
129    uint16_t            flags;
130    uint32_t            processor_uid;
131    uint8_t             local_x2apic_lint;
132    uint8_t             res[3]; /* 0 */
133} acpi_madt_locx2apicnmi_t;
134
135/* Processor Local GIC structure (B) */
136typedef struct acpi_madt_gic {
137    acpi_madt_ics_hdr_t header;
138    uint8_t             res[2]; /* 0 */
139    uint32_t            gic_id;
140    uint32_t            processor_uid;
141    uint32_t            flags;
142    uint32_t            parking_prot_version;
143    uint64_t             parked_address;
144    uint64_t             gic_address;
145} acpi_madt_gic_t;
146
147/* GIC Distributor structure (C) */
148typedef struct acpi_madt_gicdist {
149    acpi_madt_ics_hdr_t header;
150    uint8_t             res1[2];
151    uint32_t            gic_id;
152    uint64_t             gicdist_address;
153    uint32_t            system_vector_base;
154    uint8_t             res2[4];
155} acpi_madt_gicdist_t;
156
157/* MADT structure */
158typedef struct acpi_madt {
159    acpi_header_t header;
160    uint32_t       local_int_crt_address;
161    uint32_t      flags;
162    /* list of APICS */
163//    acpi_madt_ics_hdr_t ics;
164} acpi_madt_t;
165
166#pragma pack(pop)
167
168/********************************
169 **** MADT sub table helpers ****
170 ********************************/
171
172/* Retrieve the header of the first entry */
173static inline acpi_madt_ics_hdr_t*
174acpi_madt_first_ics(acpi_madt_t* tbl)
175{
176    return (acpi_madt_ics_hdr_t*)(tbl + 1);
177}
178
179/* Retrieve the next DMAR sub header */
180static inline acpi_madt_ics_hdr_t*
181acpi_madt_next_ics(acpi_madt_t* tbl,
182                   acpi_madt_ics_hdr_t* hdr)
183{
184    void* next = (uint8_t*)hdr + hdr->length;
185    void* end  = (uint8_t*)tbl + tbl->header.length;
186    if (next < end) {
187        return (acpi_madt_ics_hdr_t*)next;
188    } else {
189        return NULL;
190    }
191}
192
193/* Retrieve the DMAR sub header located at the specified index */
194static inline acpi_madt_ics_hdr_t*
195acpi_madt_ics_at(acpi_madt_t* tbl, int index)
196{
197    acpi_madt_ics_hdr_t* next = acpi_madt_first_ics(tbl);
198    while (next != NULL && index-- > 0) {
199        next = acpi_madt_next_ics(tbl, next);
200    }
201    return next;
202}
203
204/* Retrieve the next DMAR sub header of the specified type */
205static inline acpi_madt_ics_hdr_t*
206acpi_madt_next_ics_type(acpi_madt_t* tbl,
207                        acpi_madt_ics_hdr_t* hdr, int type)
208{
209    do {
210        hdr = acpi_madt_next_ics(tbl, hdr);
211        if (hdr == NULL) {
212            return NULL;
213        }
214        if (hdr->type == type) {
215            return hdr;
216        }
217    } while (1);
218}
219
220/* Retrieve the first DMAR sub header of the specified type */
221static inline acpi_madt_ics_hdr_t*
222acpi_madt_first_ics_type(acpi_madt_t* tbl, int type)
223{
224    acpi_madt_ics_hdr_t* hdr = acpi_madt_first_ics(tbl);
225    if (hdr == NULL) {
226        return NULL;
227    }
228
229    if (hdr->type != type) {
230        return acpi_madt_next_ics_type(tbl, hdr, type);
231    } else {
232        return hdr;
233    }
234}
235