1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <util.h>
9#include <assert.h>
10#include <machine/io.h>
11#include <linker.h>
12#include <plat/machine.h>
13#include <plat/machine/acpi.h>
14#include <plat/machine/devices.h>
15
16enum acpi_type {
17    ACPI_RSDP,
18    ACPI_RSDT
19};
20
21/* DMA Remapping Reporting Table */
22typedef struct acpi_dmar {
23    acpi_header_t header;
24    uint8_t       host_addr_width;
25    uint8_t       flags;
26    uint8_t       reserved[10];
27} acpi_dmar_t;
28compile_assert(acpi_dmar_packed,
29               sizeof(acpi_dmar_t) == sizeof(acpi_header_t) + 12)
30
31/* DMA Remapping Structure Header */
32typedef struct acpi_dmar_header {
33    uint16_t type;
34    uint16_t length;
35} acpi_dmar_header_t;
36compile_assert(acpi_dmar_header_packed, sizeof(acpi_dmar_header_t) == 4)
37
38/* DMA Remapping Structure Types */
39enum acpi_table_dmar_struct_type {
40    DMAR_DRHD = 0,
41    DMAR_RMRR = 1,
42    DMAR_ATSR = 2,
43};
44
45/* DMA Remapping Hardware unit Definition */
46typedef struct acpi_dmar_drhd {
47    acpi_dmar_header_t header;
48    uint8_t            flags;
49    uint8_t            reserved;
50    uint16_t           segment;
51    uint32_t           reg_base[2];
52} acpi_dmar_drhd_t;
53compile_assert(acpi_dmar_drhd_packed,
54               sizeof(acpi_dmar_drhd_t) == sizeof(acpi_dmar_header_t) + 12)
55
56/* Reserved Memory Region Reporting structure Definition */
57typedef struct acpi_dmar_devscope {
58    uint8_t  type;
59    uint8_t  length;
60    uint16_t reserved;
61    uint8_t  enum_id;
62    uint8_t  start_bus;
63    struct {
64        uint8_t dev;
65        uint8_t fun;
66    } path_0;
67} acpi_dmar_devscope_t;
68compile_assert(acpi_dmar_devscope_packed, sizeof(acpi_dmar_devscope_t) == 8)
69
70/* Reserved Memory Region Reporting structure Definition */
71typedef struct acpi_dmar_rmrr {
72    acpi_dmar_header_t   header;
73    uint16_t             reserved;
74    uint16_t             segment;
75    uint32_t             reg_base[2];
76    uint32_t             reg_limit[2];
77    acpi_dmar_devscope_t devscope_0;
78} acpi_dmar_rmrr_t;
79compile_assert(acpi_dmar_rmrr_packed, sizeof(acpi_dmar_rmrr_t) ==
80               sizeof(acpi_dmar_header_t) + 20 + sizeof(acpi_dmar_devscope_t))
81
82/* Fixed ACPI Description Table (FADT), partial as we only need flags */
83typedef struct acpi_fadt {
84    acpi_header_t  header;
85    uint8_t        reserved[76];
86    uint32_t       flags;
87} acpi_fadt_t;
88compile_assert(acpi_fadt_packed,
89               sizeof(acpi_fadt_t) == sizeof(acpi_header_t) + 80)
90
91/* Multiple APIC Description Table (MADT) */
92typedef struct acpi_madt {
93    acpi_header_t header;
94    uint32_t      apic_addr;
95    uint32_t      flags;
96} acpi_madt_t;
97compile_assert(acpi_madt_packed,
98               sizeof(acpi_madt_t) == sizeof(acpi_header_t) + 8)
99
100typedef struct acpi_madt_header {
101    uint8_t type;
102    uint8_t length;
103} acpi_madt_header_t;
104compile_assert(acpi_madt_header_packed, sizeof(acpi_madt_header_t) == 2)
105
106enum acpi_table_madt_struct_type {
107    MADT_APIC   = 0,
108    MADT_IOAPIC = 1,
109    MADT_ISO    = 2,
110    MADT_x2APIC = 9
111};
112
113typedef struct acpi_madt_apic {
114    acpi_madt_header_t header;
115    uint8_t            cpu_id;
116    uint8_t            apic_id;
117    uint32_t           flags;
118} acpi_madt_apic_t;
119compile_assert(acpi_madt_apic_packed,
120               sizeof(acpi_madt_apic_t) == sizeof(acpi_madt_header_t) + 6)
121
122typedef struct acpi_madt_x2apic {
123    acpi_madt_header_t  header;
124    uint16_t            reserved;
125    uint32_t            x2apic_id;
126    uint32_t            flags;
127    uint32_t            acpi_processor_uid;
128} acpi_madt_x2apic_t;
129compile_assert(acpi_madt_x2apic_packed,
130               sizeof(acpi_madt_x2apic_t) == sizeof(acpi_madt_header_t) + 14)
131
132typedef struct acpi_madt_ioapic {
133    acpi_madt_header_t header;
134    uint8_t            ioapic_id;
135    uint8_t            reserved[1];
136    uint32_t           ioapic_addr;
137    uint32_t           gsib;
138} acpi_madt_ioapic_t;
139compile_assert(acpi_madt_ioapic_packed,
140               sizeof(acpi_madt_ioapic_t) == sizeof(acpi_madt_header_t) + 10)
141
142typedef struct acpi_madt_iso {
143    acpi_madt_header_t header;
144    uint8_t            bus; /* always 0 (ISA) */
145    uint8_t            source;
146    uint32_t           gsi;
147    uint16_t           flags;
148} acpi_madt_iso_t;
149/* We can't assert on the sizeof acpi_madt_iso because it contains trailing
150 * padding.
151 */
152unverified_compile_assert(acpi_madt_iso_packed,
153                          OFFSETOF(acpi_madt_iso_t, flags) == sizeof(acpi_madt_header_t) + 6)
154
155/* workaround because string literals are not supported by C parser */
156const char acpi_str_rsd[]  = {'R', 'S', 'D', ' ', 'P', 'T', 'R', ' ', 0};
157const char acpi_str_fadt[] = {'F', 'A', 'C', 'P', 0};
158const char acpi_str_apic[] = {'A', 'P', 'I', 'C', 0};
159const char acpi_str_dmar[] = {'D', 'M', 'A', 'R', 0};
160
161BOOT_CODE static uint8_t acpi_calc_checksum(char *start, uint32_t length)
162{
163    uint8_t checksum = 0;
164
165    while (length > 0) {
166        checksum += *start;
167        start++;
168        length--;
169    }
170    return checksum;
171}
172
173BOOT_CODE static acpi_rsdp_t *acpi_get_rsdp(void)
174{
175    char *addr;
176
177    for (addr = (char *)BIOS_PADDR_START; addr < (char *)BIOS_PADDR_END; addr += 16) {
178        if (strncmp(addr, acpi_str_rsd, 8) == 0) {
179            if (acpi_calc_checksum(addr, ACPI_V1_SIZE) == 0) {
180                return (acpi_rsdp_t *)addr;
181            }
182        }
183    }
184    return NULL;
185}
186
187BOOT_CODE static void *acpi_table_init(void *entry, enum acpi_type table_type)
188{
189    void *acpi_table;
190    unsigned int pages_for_table;
191    unsigned int pages_for_header = 1;
192
193    /* if we need to map another page to read header */
194    unsigned long offset_in_page = (unsigned long)entry & MASK(LARGE_PAGE_BITS);
195    if (MASK(LARGE_PAGE_BITS) - offset_in_page < sizeof(acpi_rsdp_t)) {
196        pages_for_header++;
197    }
198
199    /* map in table's header */
200    acpi_table = map_temp_boot_page(entry, pages_for_header);
201
202    switch (table_type) {
203    case ACPI_RSDP: {
204        acpi_rsdp_t *rsdp_entry = (acpi_rsdp_t *)entry;
205        pages_for_table = (rsdp_entry->length + offset_in_page) / MASK(LARGE_PAGE_BITS) + 1;
206        break;
207    }
208    case ACPI_RSDT: { // RSDT, MADT, DMAR etc.
209        acpi_rsdt_t *rsdt_entry = (acpi_rsdt_t *)entry;
210        pages_for_table = (rsdt_entry->header.length + offset_in_page) / MASK(LARGE_PAGE_BITS) + 1;
211        break;
212    }
213    default:
214        printf("Error: Mapping unknown ACPI table type\n");
215        assert(false);
216        return NULL;
217    }
218
219    /* map in full table */
220    acpi_table = map_temp_boot_page(entry, pages_for_table);
221
222    return acpi_table;
223}
224
225BOOT_CODE bool_t acpi_init(acpi_rsdp_t *rsdp_data)
226{
227    acpi_rsdp_t *acpi_rsdp = acpi_get_rsdp();
228
229    if (acpi_rsdp == NULL) {
230        printf("BIOS: No ACPI support detected\n");
231        return false;
232    }
233    printf("ACPI: RSDP paddr=%p\n", acpi_rsdp);
234    acpi_rsdp = acpi_table_init(acpi_rsdp, ACPI_RSDP);
235    printf("ACPI: RSDP vaddr=%p\n", acpi_rsdp);
236
237    /* create a copy of the rsdp data */
238    *rsdp_data = *acpi_rsdp;
239
240    /* perform final validation */
241    return acpi_validate_rsdp(rsdp_data);
242}
243
244BOOT_CODE bool_t acpi_validate_rsdp(acpi_rsdp_t *acpi_rsdp)
245{
246    acpi_rsdt_t *acpi_rsdt;
247    acpi_rsdt_t *acpi_rsdt_mapped;
248
249    if (acpi_calc_checksum((char *)acpi_rsdp, ACPI_V1_SIZE) != 0) {
250        printf("BIOS: ACPIv1 information corrupt\n");
251        return false;
252    }
253
254    if (acpi_rsdp->revision > 0 && acpi_calc_checksum((char *)acpi_rsdp, sizeof(*acpi_rsdp)) != 0) {
255        printf("BIOS: ACPIv2 information corrupt\n");
256        return false;
257    }
258
259    /* verify the rsdt, even though we do not actually make use of the mapping right now */
260    acpi_rsdt = (acpi_rsdt_t *)(word_t)acpi_rsdp->rsdt_address;
261    printf("ACPI: RSDT paddr=%p\n", acpi_rsdt);
262    acpi_rsdt_mapped = (acpi_rsdt_t *)acpi_table_init(acpi_rsdt, ACPI_RSDT);
263    printf("ACPI: RSDT vaddr=%p\n", acpi_rsdt_mapped);
264
265    assert(acpi_rsdt_mapped->header.length > 0);
266    if (acpi_calc_checksum((char *)acpi_rsdt_mapped, acpi_rsdt_mapped->header.length) != 0) {
267        printf("ACPI: RSDT checksum failure\n");
268        return false;
269    }
270
271    return true;
272}
273
274BOOT_CODE uint32_t acpi_madt_scan(
275    acpi_rsdp_t *acpi_rsdp,
276    cpu_id_t    *cpu_list,
277    uint32_t    *num_ioapic,
278    paddr_t     *ioapic_paddrs
279)
280{
281    unsigned int entries;
282    uint32_t            num_cpu;
283    uint32_t            count;
284    acpi_madt_t        *acpi_madt;
285    acpi_madt_header_t *acpi_madt_header;
286
287    acpi_rsdt_t *acpi_rsdt_mapped;
288    acpi_madt_t *acpi_madt_mapped;
289    acpi_rsdt_mapped = (acpi_rsdt_t *)acpi_table_init((acpi_rsdt_t *)(word_t)acpi_rsdp->rsdt_address, ACPI_RSDT);
290
291    num_cpu = 0;
292    *num_ioapic = 0;
293
294    assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t));
295    /* Divide by uint32_t explicitly as this is the size as mandated by the ACPI standard */
296    entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(uint32_t);
297    for (count = 0; count < entries; count++) {
298        acpi_madt = (acpi_madt_t *)(word_t)acpi_rsdt_mapped->entry[count];
299        acpi_madt_mapped = (acpi_madt_t *)acpi_table_init(acpi_madt, ACPI_RSDT);
300
301        if (strncmp(acpi_str_apic, acpi_madt_mapped->header.signature, 4) == 0) {
302            printf("ACPI: MADT paddr=%p\n", acpi_madt);
303            printf("ACPI: MADT vaddr=%p\n", acpi_madt_mapped);
304            printf("ACPI: MADT apic_addr=0x%x\n", acpi_madt_mapped->apic_addr);
305            printf("ACPI: MADT flags=0x%x\n", acpi_madt_mapped->flags);
306
307            acpi_madt_header = (acpi_madt_header_t *)(acpi_madt_mapped + 1);
308
309            while ((char *)acpi_madt_header < (char *)acpi_madt_mapped + acpi_madt_mapped->header.length) {
310                switch (acpi_madt_header->type) {
311                /* ACPI specifies the following rules when listing APIC IDs:
312                 *  - Boot processor is listed first
313                 *  - For multi-threaded processors, BIOS should list the first logical
314                 *    processor of each of the individual multi-threaded processors in MADT
315                 *    before listing any of the second logical processors.
316                 *  - APIC IDs < 0xFF should be listed in APIC subtable, APIC IDs >= 0xFF
317                 *    should be listed in X2APIC subtable */
318                case MADT_APIC: {
319                    /* what Intel calls apic_id is what is called cpu_id in seL4! */
320                    uint8_t  cpu_id = ((acpi_madt_apic_t *)acpi_madt_header)->apic_id;
321                    uint32_t flags  = ((acpi_madt_apic_t *)acpi_madt_header)->flags;
322                    if (flags == 1) {
323                        printf("ACPI: MADT_APIC apic_id=0x%x\n", cpu_id);
324                        if (num_cpu == CONFIG_MAX_NUM_NODES) {
325                            printf("ACPI: Not recording this APIC, only support %d\n", CONFIG_MAX_NUM_NODES);
326                        } else {
327                            cpu_list[num_cpu] = cpu_id;
328                            num_cpu++;
329                        }
330                    }
331                    break;
332                }
333                case MADT_x2APIC: {
334                    uint32_t cpu_id = ((acpi_madt_x2apic_t *)acpi_madt_header)->x2apic_id;
335                    uint32_t flags  = ((acpi_madt_x2apic_t *)acpi_madt_header)->flags;
336                    if (flags == 1) {
337                        printf("ACPI: MADT_x2APIC apic_id=0x%x\n", cpu_id);
338                        if (num_cpu == CONFIG_MAX_NUM_NODES) {
339                            printf("ACPI: Not recording this APIC, only support %d\n", CONFIG_MAX_NUM_NODES);
340                        } else {
341                            cpu_list[num_cpu] = cpu_id;
342                            num_cpu++;
343                        }
344                    }
345                    break;
346                }
347                case MADT_IOAPIC:
348                    printf(
349                        "ACPI: MADT_IOAPIC ioapic_id=%d ioapic_addr=0x%x gsib=%d\n",
350                        ((acpi_madt_ioapic_t *)acpi_madt_header)->ioapic_id,
351                        ((acpi_madt_ioapic_t *)acpi_madt_header)->ioapic_addr,
352                        ((acpi_madt_ioapic_t *)acpi_madt_header)->gsib
353                    );
354                    if (*num_ioapic == CONFIG_MAX_NUM_IOAPIC) {
355                        printf("ACPI: Not recording this IOAPIC, only support %d\n", CONFIG_MAX_NUM_IOAPIC);
356                    } else {
357                        ioapic_paddrs[*num_ioapic] = ((acpi_madt_ioapic_t *)acpi_madt_header)->ioapic_addr;
358                        (*num_ioapic)++;
359                    }
360                    break;
361                case MADT_ISO:
362                    printf("ACPI: MADT_ISO bus=%d source=%d gsi=%d flags=0x%x\n",
363                           ((acpi_madt_iso_t *)acpi_madt_header)->bus,
364                           ((acpi_madt_iso_t *)acpi_madt_header)->source,
365                           ((acpi_madt_iso_t *)acpi_madt_header)->gsi,
366                           ((acpi_madt_iso_t *)acpi_madt_header)->flags);
367                    break;
368                default:
369                    break;
370                }
371                acpi_madt_header = (acpi_madt_header_t *)((char *)acpi_madt_header + acpi_madt_header->length);
372            }
373        }
374    }
375
376    printf("ACPI: %d CPU(s) detected\n", num_cpu);
377
378    return num_cpu;
379}
380
381BOOT_CODE bool_t acpi_fadt_scan(
382    acpi_rsdp_t *acpi_rsdp
383)
384{
385    unsigned int entries;
386    uint32_t            count;
387    acpi_fadt_t        *acpi_fadt;
388
389    acpi_rsdt_t *acpi_rsdt_mapped;
390    acpi_fadt_t *acpi_fadt_mapped;
391    acpi_rsdt_mapped = (acpi_rsdt_t *)acpi_table_init((acpi_rsdt_t *)(word_t)acpi_rsdp->rsdt_address, ACPI_RSDT);
392
393    assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t));
394    /* Divide by uint32_t explicitly as this is the size as mandated by the ACPI standard */
395    entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(uint32_t);
396    for (count = 0; count < entries; count++) {
397        acpi_fadt = (acpi_fadt_t *)(word_t)acpi_rsdt_mapped->entry[count];
398        acpi_fadt_mapped = (acpi_fadt_t *)acpi_table_init(acpi_fadt, ACPI_RSDT);
399
400        if (strncmp(acpi_str_fadt, acpi_fadt_mapped->header.signature, 4) == 0) {
401            printf("ACPI: FADT paddr=%p\n", acpi_fadt);
402            printf("ACPI: FADT vaddr=%p\n", acpi_fadt_mapped);
403            printf("ACPI: FADT flags=0x%x\n", acpi_fadt_mapped->flags);
404
405            if (config_set(CONFIG_USE_LOGICAL_IDS) &&
406                acpi_fadt_mapped->flags & BIT(19)) {
407                printf("system requires apic physical mode\n");
408                return false;
409            }
410        }
411    }
412
413    return true;
414}
415
416BOOT_CODE void acpi_dmar_scan(
417    acpi_rsdp_t *acpi_rsdp,
418    paddr_t     *drhu_list,
419    uint32_t    *num_drhu,
420    uint32_t     max_drhu_list_len,
421    acpi_rmrr_list_t *rmrr_list
422)
423{
424    word_t i;
425    unsigned int entries;
426    uint32_t count;
427    uint32_t reg_basel, reg_baseh;
428    int rmrr_count;
429    dev_id_t dev_id;
430
431    acpi_dmar_t          *acpi_dmar;
432    acpi_dmar_header_t   *acpi_dmar_header;
433    acpi_dmar_rmrr_t     *acpi_dmar_rmrr;
434    acpi_dmar_devscope_t *acpi_dmar_devscope;
435
436    acpi_rsdt_t *acpi_rsdt_mapped;
437    acpi_dmar_t *acpi_dmar_mapped;
438
439    acpi_rsdt_mapped = (acpi_rsdt_t *)acpi_table_init((acpi_rsdt_t *)(word_t)acpi_rsdp->rsdt_address, ACPI_RSDT);
440
441    *num_drhu = 0;
442    rmrr_count = 0;
443
444    assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t));
445    entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(uint32_t);
446    for (count = 0; count < entries; count++) {
447        acpi_dmar = (acpi_dmar_t *)(word_t)acpi_rsdt_mapped->entry[count];
448        acpi_dmar_mapped = (acpi_dmar_t *)acpi_table_init(acpi_dmar, ACPI_RSDT);
449
450        if (strncmp(acpi_str_dmar, acpi_dmar_mapped->header.signature, 4) == 0) {
451            printf("ACPI: DMAR paddr=%p\n", acpi_dmar);
452            printf("ACPI: DMAR vaddr=%p\n", acpi_dmar_mapped);
453            printf("ACPI: IOMMU host address width: %d\n", acpi_dmar_mapped->host_addr_width + 1);
454            acpi_dmar_header = (acpi_dmar_header_t *)(acpi_dmar_mapped + 1);
455
456            while ((char *)acpi_dmar_header < (char *)acpi_dmar_mapped + acpi_dmar_mapped->header.length) {
457                switch (acpi_dmar_header->type) {
458
459                case DMAR_DRHD:
460                    if (*num_drhu == max_drhu_list_len) {
461                        printf("ACPI: too many IOMMUs, disabling IOMMU support\n");
462                        /* try to increase MAX_NUM_DRHU in config.h */
463                        *num_drhu = 0; /* report zero IOMMUs */
464                        return;
465                    }
466                    reg_basel = ((acpi_dmar_drhd_t *)acpi_dmar_header)->reg_base[0];
467                    reg_baseh = ((acpi_dmar_drhd_t *)acpi_dmar_header)->reg_base[1];
468                    /* check if value fits into uint32_t */
469                    if (reg_baseh != 0) {
470                        printf("ACPI: DMAR_DRHD reg_base exceeds 32 bit, disabling IOMMU support\n");
471                        /* try to make BIOS map it below 4G */
472                        *num_drhu = 0; /* report zero IOMMUs */
473                        return;
474                    }
475                    drhu_list[*num_drhu] = (paddr_t)reg_basel;
476                    (*num_drhu)++;
477                    break;
478
479                case DMAR_RMRR:
480                    /* loop through all device scopes of this RMRR */
481                    acpi_dmar_rmrr = (acpi_dmar_rmrr_t *)acpi_dmar_header;
482                    if (acpi_dmar_rmrr->reg_base[1] != 0 ||
483                        acpi_dmar_rmrr->reg_limit[1] != 0) {
484                        printf("ACPI: RMRR device above 4GiB, disabling IOMMU support\n");
485                        *num_drhu = 0;
486                        return ;
487                    }
488
489                    for (i = 0; i <= (acpi_dmar_header->length - sizeof(acpi_dmar_rmrr_t)) / sizeof(acpi_dmar_devscope_t); i++) {
490                        acpi_dmar_devscope = &acpi_dmar_rmrr->devscope_0 + i;
491
492                        if (acpi_dmar_devscope->type != 1) {
493                            /* FIXME - bugzilla bug 170 */
494                            printf("ACPI: RMRR device scope: non-PCI-Endpoint-Devices not supported yet, disabling IOMMU support\n");
495                            *num_drhu = 0; /* report zero IOMMUs */
496                            return;
497                        }
498
499                        if (acpi_dmar_devscope->length > sizeof(acpi_dmar_devscope_t)) {
500                            /* FIXME - bugzilla bug 170 */
501                            printf("ACPI: RMRR device scope: devices behind bridges not supported yet, disabling IOMMU support\n");
502                            *num_drhu = 0; /* report zero IOMMUs */
503                            return;
504                        }
505
506                        dev_id =
507                            get_dev_id(
508                                acpi_dmar_devscope->start_bus,
509                                acpi_dmar_devscope->path_0.dev,
510                                acpi_dmar_devscope->path_0.fun
511                            );
512
513                        if (rmrr_count == CONFIG_MAX_RMRR_ENTRIES) {
514                            printf("ACPI: Too many RMRR entries, disabling IOMMU support\n");
515                            *num_drhu = 0;
516                            return;
517                        }
518                        printf("\tACPI: registering RMRR entry for region for device: bus=0x%x dev=0x%x fun=0x%x\n",
519                               acpi_dmar_devscope->start_bus,
520                               acpi_dmar_devscope->path_0.dev,
521                               acpi_dmar_devscope->path_0.fun
522                              );
523
524                        rmrr_list->entries[rmrr_count].device = dev_id;
525                        rmrr_list->entries[rmrr_count].base = acpi_dmar_rmrr->reg_base[0];
526                        rmrr_list->entries[rmrr_count].limit = acpi_dmar_rmrr->reg_limit[0];
527                        rmrr_count++;
528                    }
529                    break;
530
531                case DMAR_ATSR:
532                    /* not implemented yet */
533                    break;
534
535                default:
536                    printf("ACPI: Unknown DMA remapping structure type: %x\n", acpi_dmar_header->type);
537                }
538                acpi_dmar_header = (acpi_dmar_header_t *)((char *)acpi_dmar_header + acpi_dmar_header->length);
539            }
540        }
541    }
542    rmrr_list->num = rmrr_count;
543    printf("ACPI: %d IOMMUs detected\n", *num_drhu);
544}
545