1/**
2 * \file
3 * \brief ACPI management
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2016 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, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <barrelfish/barrelfish.h>
17#include <barrelfish/nameservice_client.h>
18#include <barrelfish_kpi/types.h>
19#include <acpi.h>
20#include <mm/mm.h>
21#include <octopus/getset.h>
22#include <octopus/barrier.h>
23#include <skb/skb.h>
24#include <hw_records.h>
25#include <pci/confspace/pci_confspace.h>
26#include "acpi_shared.h"
27#include "acpi_debug.h"
28
29
30#include <trace/trace.h>
31
32#define PCI_LNK_DEV_STRING              "PNP0C0F"
33#define HPET_HID_STRING                 "PNP0103"
34#define METHOD_NAME__DIS                "_DIS"
35
36// hpet(base address, nTimers)
37#define SKB_SCHEMA_HPET \
38     "hpet(%" PRIu64 ", %" PRIu8 ")."
39
40struct pci_resources {
41    uint8_t minbus, maxbus;
42    lpaddr_t minmem, maxmem;
43    struct pci_address addr;
44};
45
46struct memrange {
47    lpaddr_t min;
48    lpaddr_t limit;
49};
50
51#define MAX_RESERVED_MEM_REGIONS 32
52// Hack: reserved memory regions (eg. PCIe config space mapping)
53static struct memrange reserved_memory[MAX_RESERVED_MEM_REGIONS];
54static int n_reserved_memory_regions;
55
56
57static ACPI_STATUS pci_resource_walker(ACPI_RESOURCE *resource, void *context)
58{
59    struct pci_resources *ret = context;
60//    uint64_t granularity, min, max, translationoffset, addrlength;
61    lpaddr_t granularity, min, max, translationoffset, addrlength;
62
63    switch (resource->Type) {
64    case ACPI_RESOURCE_TYPE_ADDRESS16:
65        granularity = resource->Data.Address16.Address.Granularity;
66        min = resource->Data.Address16.Address.Minimum;
67        max = resource->Data.Address16.Address.Maximum;
68        translationoffset = resource->Data.Address16.Address.TranslationOffset;
69        addrlength = resource->Data.Address16.Address.AddressLength;
70        break;
71
72    case ACPI_RESOURCE_TYPE_ADDRESS32:
73        granularity = resource->Data.Address32.Address.Granularity;
74        min = resource->Data.Address32.Address.Minimum;
75        max = resource->Data.Address32.Address.Maximum;
76        translationoffset = resource->Data.Address32.Address.TranslationOffset;
77        addrlength = resource->Data.Address32.Address.AddressLength;
78        break;
79
80    case ACPI_RESOURCE_TYPE_ADDRESS64:
81        granularity = resource->Data.Address64.Address.Granularity;
82        min = resource->Data.Address64.Address.Minimum;
83        max = resource->Data.Address64.Address.Maximum;
84        translationoffset = resource->Data.Address64.Address.TranslationOffset;
85        addrlength = resource->Data.Address32.Address.AddressLength;
86        break;
87
88    default:
89        return AE_OK;
90    }
91
92    /* Ignore bogus entries with zero length */
93    if (addrlength == 0) {
94        ACPI_DEBUG("Warning: ignoring zero-length address resource\n");
95        return AE_OK;
96    }
97
98    /* TODO: handle non-fixed regions. Does anything other than QEMU do this? */
99    if (resource->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED ||
100        resource->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED) {
101        ACPI_DEBUG("Warning: Treating non-fixed address range resource as fixed\n");
102    }
103
104    switch (resource->Data.Address.ResourceType) {
105    case ACPI_BUS_NUMBER_RANGE:
106        assert(max > 0);
107        assert(ret->maxbus == 0); /* shouldn't have more than one of these */
108        ret->minbus = min;
109        ret->maxbus = max;
110        break;
111
112    case ACPI_MEMORY_RANGE:
113        ACPI_DEBUG("PCI mem range %lx-%lx granularity 0x%lx translation offset "
114                  " 0x%lx length 0x%lx prodcons %u decode %u writeprot %u"
115                  " caching %u rangetype %u translation %u\n", min, max,
116                  granularity, translationoffset, addrlength,
117                  resource->Data.Address.ProducerConsumer,
118                  resource->Data.Address.Decode,
119                  resource->Data.Address.Info.Mem.WriteProtect,
120                  resource->Data.Address.Info.Mem.Caching,
121                  resource->Data.Address.Info.Mem.RangeType,
122                  resource->Data.Address.Info.Mem.Translation);
123/*
124        // check for overlaps with reserved memory regions
125        for (int i = 0; i < n_reserved_memory_regions; i++) {
126            struct memrange *range = &reserved_memory[i];
127            if (min < range->limit && max >= range->min) {
128                if (min < range->limit && min >= range->min) {
129                    // overlaps with min: take top part
130                    min = range->limit;
131                } else if (max - range->limit > range->min - min) {
132                    // take top part
133                    min = range->limit;
134                } else {
135                    // take bottom part
136                    max = range->min - 1;
137                }
138                if (min > max) {
139                    min = max = 0;
140                }
141                ACPI_DEBUG("mem range overlaps reserved space [%lx,%lx], truncated"
142                          " to %lx-%lx\n", range->min, range->limit, min, max);
143            }
144        }
145*/
146        skb_add_fact("rootbridge_address_window(addr(%u, %u, %u), mem(%"PRIuLPADDR", %"PRIuLPADDR")).",
147            ret->addr.bus, ret->addr.device, ret->addr.function,
148            min, max);
149        if (ret->minmem == ret->maxmem) {
150            /* this is the first region we've seen */
151            ret->minmem = min;
152            ret->maxmem = max;
153        } else if (min == ret->maxmem + 1) {
154            /* this region extends the existing region */
155            ret->maxmem = max;
156        } else if (max - min > ret->maxmem - ret->minmem) {
157            /* this region is bigger than the existing region */
158            ret->minmem = min;
159            ret->maxmem = max;
160        }
161        break;
162    }
163
164    return AE_OK;
165}
166
167#ifdef ACPI_SERVICE_DEBUG
168static ACPI_STATUS resource_printer(ACPI_RESOURCE *res, void *context)
169{
170    switch(res->Type) {
171    case ACPI_RESOURCE_TYPE_END_TAG:
172        return AE_OK;
173
174    case ACPI_RESOURCE_TYPE_ADDRESS16:
175        printf("addr16\n");
176        break;
177    case ACPI_RESOURCE_TYPE_ADDRESS32:
178        printf("addr32\n");
179        break;
180    case ACPI_RESOURCE_TYPE_ADDRESS64:
181        printf("length = %"PRIu32", gran = %"PRIx64", min = %"PRIx64", max = %"PRIx64", transoff "
182               "= %"PRIx64", addrlen = %"PRIx64", index = %hhu, strlen = %hu, string = %s",
183               res->Length, res->Data.Address64.Address.Granularity,
184               res->Data.Address64.Address.Minimum,
185               res->Data.Address64.Address.Maximum,
186               res->Data.Address64.Address.TranslationOffset,
187               res->Data.Address64.Address.AddressLength,
188               res->Data.Address64.ResourceSource.Index,
189               res->Data.Address64.ResourceSource.StringLength,
190               res->Data.Address64.ResourceSource.StringPtr
191               );
192        break;
193
194    case ACPI_RESOURCE_TYPE_IRQ:
195        {
196            ACPI_RESOURCE_IRQ *irqres = &res->Data.Irq;
197
198            printf("%s, %s triggered, active %s, ",
199                   irqres->Sharable ? "shared" : "exclusive",
200                   irqres->Triggering ? "edge" : "level",
201                   irqres->Polarity ? "low" : "high");
202
203            if (irqres->InterruptCount > 0) {
204                printf("IRQs:");
205                for (int i = 0; i < irqres->InterruptCount; i++) {
206                    printf(" %d", irqres->Interrupts[i]);
207                }
208                printf(".\n");
209            } else {
210                printf("no IRQ.\n");
211            }
212        }
213        break;
214
215    case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
216        {
217            ACPI_RESOURCE_EXTENDED_IRQ *irqres = &res->Data.ExtendedIrq;
218
219            printf("%s, %s triggered, active %s, ",
220                   irqres->Sharable ? "shared" : "exclusive",
221                   irqres->Triggering ? "edge" : "level",
222                   irqres->Polarity ? "low" : "high");
223
224            if (irqres->InterruptCount > 0) {
225                printf("IRQs:");
226                for (int i = 0; i < irqres->InterruptCount; i++) {
227                    printf(" %"PRIu32, irqres->Interrupts[i]);
228                }
229            } else {
230                printf("no IRQ");
231            }
232
233            ACPI_RESOURCE_SOURCE *src = &irqres->ResourceSource;
234
235            if(src->StringLength > 0) {
236                printf(", resource index %d, source %.*s\n", src->Index,
237                       src->StringLength, src->StringPtr);
238            } else {
239                printf(".\n");
240            }
241        }
242        break;
243
244    default:
245        printf("resource_printer: Unexpected resource type %"PRIu32"\n", res->Type);
246        break;
247    }
248
249    return AE_OK;
250}
251#endif
252
253ACPI_STATUS acpi_eval_integer(ACPI_HANDLE handle, const char *name, ACPI_INTEGER *ret)
254{
255    assert(ret != NULL);
256    ACPI_STATUS as;
257    char intbuf[sizeof(ACPI_OBJECT)];
258    ACPI_BUFFER intbufobj = {.Length = sizeof(intbuf), .Pointer = intbuf};
259
260    as = AcpiEvaluateObjectTyped(handle, (CONST_CAST)name, NULL, &intbufobj, ACPI_TYPE_INTEGER);
261    if (ACPI_SUCCESS(as)) {
262        ACPI_OBJECT *obj = intbufobj.Pointer;
263        *ret = obj->Integer.Value;
264    }
265
266    return as;
267}
268
269static ACPI_STATUS fixed_resource_walker(ACPI_RESOURCE *resource, void *context)
270{
271    if (resource->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
272        struct memrange range = {
273            .min = resource->Data.FixedMemory32.Address,
274            .limit = resource->Data.FixedMemory32.Address
275                + resource->Data.FixedMemory32.AddressLength
276        };
277        ACPI_DEBUG("fixed memory resource claimed: 0x%"PRIxLPADDR"-%"PRIxLPADDR"\n",
278                  range.min, range.limit);
279
280        /* XXX: TODO: insert something in the SKB */
281        assert(n_reserved_memory_regions < MAX_RESERVED_MEM_REGIONS);
282        reserved_memory[n_reserved_memory_regions++] = range;
283        skb_add_fact("fixed_memory(%"PRIuLPADDR",%"PRIuLPADDR").", range.min,
284            range.limit);
285    }
286
287    return AE_OK;
288}
289
290static ACPI_STATUS reserve_resources(ACPI_HANDLE handle, UINT32 level,
291                                     void *context, void **retval)
292{
293    ACPI_STATUS as;
294
295    /* walk _CRS resources looking for fixed resources */
296    as = AcpiWalkResources(handle, METHOD_NAME__CRS, fixed_resource_walker, NULL);
297    if (ACPI_FAILURE(as)) {
298        return as;
299    }
300
301    return AE_OK;
302}
303
304/**
305 * \brief Get IRQ routing table by querying _PRT method.
306 *
307 * \param handle        Handle to _PRT method.
308 * \param bus           Bus number this _PRT method is for.
309 */
310static void get_irq_routing(ACPI_HANDLE handle, uint8_t bus)
311{
312    ACPI_STATUS as;
313    char prtbuf[8192];
314    ACPI_BUFFER bufobj = {.Length = sizeof(prtbuf), .Pointer = prtbuf};
315
316    char namebuf[256];
317    ACPI_BUFFER namebufobj = {.Length = sizeof(namebuf), .Pointer = namebuf};
318
319    as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &namebufobj);
320    if (ACPI_FAILURE(as)) {
321        ACPI_DEBUG("No name found: %s\n", AcpiFormatException(as));
322        namebuf[0] = 0;
323    } else {
324        assert(namebufobj.Pointer == namebuf);
325    }
326
327    /* do we have an interrupt routing table? */
328    as = AcpiGetIrqRoutingTable(handle, &bufobj);
329    if (ACPI_FAILURE(as)) {
330        ACPI_DEBUG("No PCI IRQ routing table for (%s) bus %"PRIu8": %s\n", namebuf, bus, AcpiFormatException(as));
331        return;
332    }
333
334    ACPI_DEBUG("PCI IRQ routing table for (%s) bus %"PRIu8":\n", namebuf, bus);
335    ACPI_PCI_ROUTING_TABLE *prt = bufobj.Pointer;
336    for (; prt->Length; prt = (void *)prt + prt->Length) {
337        uint16_t device = (prt->Address >> 16) & 0xffff;
338        assert((prt->Address & 0xffff) == 0xffff); // any function
339        ACPI_DEBUG(" device %u pin %"PRIu32" %s (index %"PRIu32")\n",
340               device, prt->Pin, *(prt->Source) ? prt->Source : "GSI",
341               prt->SourceIndex);
342
343        if (*prt->Source == 0) {
344            /* this is a global interrupt number */
345            skb_add_fact("prt(addr(%"PRIu8", %"PRIu16", _), %"PRIu32", gsi(%"PRIu32")).",
346                         bus, device, prt->Pin, prt->SourceIndex);
347            continue;
348        }
349
350        ACPI_HANDLE source;
351        as = AcpiGetHandle(handle, prt->Source, &source);
352        if (ACPI_FAILURE(as)) {
353            ACPI_DEBUG("  failed lookup: %s\n", AcpiFormatException(as));
354            continue;
355        }
356
357        assert(device < PCI_NDEVICES);
358        assert(prt->Pin < PCI_NINTPINS);
359
360        char *esource = calloc(strlen(prt->Source) * 2, 1);
361        for(int i = 0, j = 0; i < strlen(prt->Source) + 1; i++, j++) {
362            esource[j] = prt->Source[i];
363            if(prt->Source[i] == '\\') {
364                esource[++j] = '\\';
365            }
366        }
367        skb_add_fact("prt(addr(%"PRIu8", %"PRIu16", _), %"PRIu32", pir(\"%s\")).",
368                     bus, device, prt->Pin, esource);
369
370#ifdef ACPI_SERVICE_DEBUG /* debug code to dump resources */
371        ACPI_DEBUG("  INITIAL:  ");
372        as = AcpiWalkResources(source, METHOD_NAME__CRS,
373                               resource_printer, NULL);
374        if (ACPI_FAILURE(as)) {
375            ACPI_DEBUG("  failed walking _CRS: %s\n", AcpiFormatException(as));
376        }
377
378        ACPI_DEBUG("  POSSIBLE: ");
379        as = AcpiWalkResources(source, METHOD_NAME__PRS,
380                               resource_printer, NULL);
381        if (ACPI_FAILURE(as)) {
382            ACPI_DEBUG("  failed walking _PRS: %s\n", AcpiFormatException(as));
383        }
384#endif
385
386        uint8_t data[512];
387        ACPI_BUFFER buf = { .Length = sizeof(data), .Pointer = &data };
388        as = AcpiGetPossibleResources(source, &buf);
389        if (ACPI_FAILURE(as)) {
390            ACPI_DEBUG("  failed retrieving _PRS: %s\n",
391                      AcpiFormatException(as));
392            free(esource);
393            continue;
394        }
395
396        for(ACPI_RESOURCE *res = buf.Pointer;
397            (void *)res < buf.Pointer + buf.Length;
398            res = (ACPI_RESOURCE *)(((char *)res) + res->Length)) {
399
400            if(res->Type == ACPI_RESOURCE_TYPE_END_TAG) {
401                break;
402            }
403
404            switch(res->Type) {
405            case ACPI_RESOURCE_TYPE_IRQ:
406            {
407                ACPI_RESOURCE_IRQ *irqres = &res->Data.Irq;
408                //printf("IRQs:");
409                for (int i = 0; i < irqres->InterruptCount; i++) {
410                    skb_add_fact("pir(\"%s\", %u).",
411                                 esource, irqres->Interrupts[i]);
412                    //printf(" %d", irqres->Interrupts[i]);
413                }
414                //printf("\n");
415                break;
416            }
417
418            case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
419            {
420                ACPI_RESOURCE_EXTENDED_IRQ *irqres = &res->Data.ExtendedIrq;
421                //printf("Extended IRQs:");
422                for (int i = 0; i < irqres->InterruptCount; i++) {
423                    //printf(" %d", irqres->Interrupts[i]);
424                    skb_add_fact("pir(\"%s\", %"PRIu32").",
425                                 esource, irqres->Interrupts[i]);
426                }
427                //printf("\n");
428                break;
429            }
430
431            default:
432                printf("Unknown resource type: %"PRIu32"\n", res->Type);
433                USER_PANIC("NYI");
434                break;
435            }
436        }
437
438        errval_t err;
439        err = skb_execute_query("add_pcilnk_controller_by_name(\"%s\", Lbl), "
440                "writeln(Lbl).", esource);
441        if(err_is_fail(err)){
442            DEBUG_SKB_ERR(err, "add_pcilnk_controller_by_name");
443        }
444        free(esource);
445    }
446}
447
448errval_t acpi_get_irqtable_device(ACPI_HANDLE parent,
449        acpi_pci_address_t device, ACPI_HANDLE *child, uint8_t bus)
450{
451
452    *child = NULL;
453
454    if(parent == NULL) {
455        return ACPI_ERR_INVALID_PATH_NAME;
456    }
457
458    // For each children of parent
459    for(;;) {
460        ACPI_STATUS as =
461            AcpiGetNextObject(ACPI_TYPE_DEVICE, parent, *child, child);
462
463        if(as == AE_NOT_FOUND || *child == NULL) {
464            break; //Goto error out
465        }
466
467        if(ACPI_FAILURE(as)) {
468            ACPI_DEBUG("Error looking up ACPI children.\n");
469            abort();
470        }
471
472        // look for a _ADR node, which tells us the bridge's configuration space
473        ACPI_INTEGER addr;
474        as = acpi_eval_integer(*child, "_ADR", &addr);
475        if (ACPI_FAILURE(as)) {
476            ACPI_DEBUG("No _ADR method found !?!.\n");
477            continue;
478        }
479
480        acpi_pci_address_t bridgeaddr;
481        bridgeaddr.bus = 0;
482        bridgeaddr.device = (addr >> 16) & 0xffff;
483        bridgeaddr.function = addr & 0xffff;
484
485        if(device.device == bridgeaddr.device
486           && device.function == bridgeaddr.function) {
487            get_irq_routing(*child, bus);
488            return SYS_ERR_OK;
489        }
490    }
491
492    // Error output
493    char namebuf[128];
494    ACPI_BUFFER buf = { .Length = sizeof(namebuf), .Pointer = namebuf };
495    ACPI_STATUS s;
496    s = AcpiGetName(parent, ACPI_FULL_PATHNAME, &buf);
497    assert(ACPI_SUCCESS(s));
498    // LH: It seems this is not a fatal condition, but I am really not sure.
499    ACPI_DEBUG("acpi_service: No matching child bridge found. Parent '%s'. Child %"PRIu8
500           ", %"PRIu8", %"PRIu8" \n", namebuf, bus, device.device, device.function);
501    return ACPI_ERR_NO_CHILD_BRIDGE;
502}
503
504static ACPI_STATUS add_pci_lnk_device(ACPI_HANDLE handle, UINT32 level,
505                                  void *context, void **retval)
506{
507    ACPI_STATUS as;
508    char namebuf[128];
509    ACPI_BUFFER bufobj = {.Length = sizeof(namebuf), .Pointer = namebuf};
510
511    /* get the node's name */
512    as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &bufobj);
513    if (ACPI_FAILURE(as)) {
514        ACPI_DEBUG("Cannot resolve name of PCI Link device\n");
515        return as;
516    }
517    assert(bufobj.Pointer == namebuf);
518    ACPI_DEBUG("Discovered PCI Link device (%s). Disabling\n", namebuf);
519    as = AcpiEvaluateObject(handle, METHOD_NAME__DIS, NULL, NULL);
520    if (ACPI_FAILURE(as)) {
521        printf("acpi: Warning: Cannot execute _DIS of PCI Link device (%s)\n", namebuf);
522        return AE_OK;
523    }
524
525    return AE_OK;
526}
527
528
529static ACPI_STATUS add_pci_device(ACPI_HANDLE handle, UINT32 level,
530                                  void *context, void **retval)
531{
532    ACPI_STATUS as;
533    char namebuf[128];
534    ACPI_BUFFER bufobj = {.Length = sizeof(namebuf), .Pointer = namebuf};
535
536    /* get the node's name */
537    as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &bufobj);
538    if (ACPI_FAILURE(as)) {
539        return as;
540    }
541    assert(bufobj.Pointer == namebuf);
542
543    ACPI_HANDLE handle2;
544    as = AcpiGetHandle(NULL, namebuf, &handle2);
545    ACPI_DEBUG("acpi get handle for %s\n", namebuf);
546    assert(ACPI_SUCCESS(as) && handle == handle2);
547
548
549    /* look for a _ADR node, which tells us the bridge's configuration space */
550    ACPI_INTEGER addr;
551    as = acpi_eval_integer(handle, "_ADR", &addr);
552    if (ACPI_FAILURE(as)) {
553        if (as != AE_NOT_FOUND) {
554            debug_printf("add_pci_device: cannot evaluate _ADR: status=%x \n", as);
555        }
556        return AE_OK;
557    }
558
559    struct pci_address bridgeaddr;
560    bridgeaddr.bus = 0;
561    bridgeaddr.device = (addr >> 16) & 0xffff;
562    bridgeaddr.function = addr & 0xffff;
563
564    /* look for a _BBN node, which tells us the bus number on a multi-root box */
565    ACPI_INTEGER busnum;
566    as = acpi_eval_integer(handle, "_BBN", &busnum);
567    if (ACPI_SUCCESS(as)) {
568        bridgeaddr.bus = busnum;
569    }
570
571    /* walk resources looking for the child bus ranges */
572    struct pci_resources resources;
573    memset(&resources, 0, sizeof(resources));
574
575    resources.addr = bridgeaddr;
576
577#ifdef ACPI_SERVICE_DEBUG
578    printf("\nstart PRS\n");
579    as = AcpiWalkResources(handle, METHOD_NAME__PRS, resource_printer,
580                           NULL);
581    printf("\nPRS finished\n");
582    if (ACPI_FAILURE(as)) {
583        printf("\nPRS failed. Status = %"PRIu32"\n", as);
584//        return as;
585    }
586#endif
587    as = AcpiWalkResources(handle, METHOD_NAME__CRS, pci_resource_walker,
588                           &resources);
589    if (ACPI_FAILURE(as)) {
590        return as;
591    }
592
593    if (resources.maxbus == 0) {
594        ACPI_DEBUG("%s: invalid PCI root at %u:%u:%u? Ignored.\n",
595               namebuf, bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function);
596        return AE_OK;
597    }
598
599    get_irq_routing(handle, bridgeaddr.bus);
600
601    ACPI_DEBUG("%s: root at %u:%u:%u child buses %u-%u memory 0x%lx-%lx\n",
602           namebuf, bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function,
603           resources.minbus, resources.maxbus, resources.minmem,
604           resources.maxmem + 1);
605
606    skb_add_fact("rootbridge(addr(%u,%u,%u),childbus(%u,%u),mem(%" PRIuPTR ",%" PRIuPTR ")).",
607           bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function,
608           resources.minbus, resources.maxbus, resources.minmem,
609           resources.maxmem);
610
611    // octopus record for rootbridge
612    ACPI_DEBUG("acpi_node: %s\n", namebuf);
613    static char* format = "hw.pci.rootbridge. { bus: %lu, device: %lu, function: %lu, maxbus: %lu, acpi_node: '%s' }";
614    errval_t err = oct_mset(SET_SEQUENTIAL, format,
615            bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function,
616            resources.maxbus, namebuf);
617    if (err_is_fail(err)) {
618        USER_PANIC_ERR(err, "oct_mset failed.\n");
619    }
620    // end
621
622    // XXX: enable PCIe for bridge programming
623    /*
624    pcie_enable();
625    pci_add_root(bridgeaddr, resources.maxbus, handle);
626    pcie_disable();*/
627
628    return AE_OK;
629}
630
631struct hpet_data {
632    int uid;
633    uint8_t page;
634    uint8_t attr;
635    lpaddr_t base_address;
636};
637
638static ACPI_STATUS hpet_resource_walker(ACPI_RESOURCE *resource, void *context)
639{
640    struct hpet_data *ret = context;
641    ACPI_STATUS as;
642
643    ACPI_DEBUG("enter: hpet_resource walker");
644    ACPI_RESOURCE_ADDRESS64 addr64;
645    as = AcpiResourceToAddress64(resource, &addr64);
646    if(ACPI_SUCCESS(as)){
647        ret->base_address = addr64.Address.Minimum;
648        return as;
649    }
650
651    if(resource->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
652        ACPI_RESOURCE_FIXED_MEMORY32 * fm = &resource->Data.FixedMemory32;
653        ret->base_address = fm->Address;
654        return AE_OK;
655    }
656
657    if(resource->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
658        printf("(Unexpectedly) Found HPET Extended IRQs in ACPI!");
659        return AE_OK;
660    }
661
662    ACPI_DEBUG("unknown ressource type: %d\n", resource->Type);
663    return AE_OK;
664}
665
666static ACPI_STATUS add_hpet_device(ACPI_HANDLE handle, UINT32 level,
667                                   void *context, void **retval)
668{
669    ACPI_STATUS as = AE_OK;
670    ACPI_DEBUG("resource walk add_hpet_device: Enter\n");
671
672    struct hpet_data data;
673
674    ACPI_INTEGER acint;
675    as = acpi_eval_integer(handle, "_UID", &acint);
676    if(ACPI_SUCCESS(as)){
677        data.uid = acint;
678    } else {
679        // _UID implementation is optional if only one hpet is available
680        ACPI_DEBUG("Could not evaluate _UID of HPET\n");
681        data.uid = 0;
682    }
683
684    as = acpi_eval_integer(handle, "PAGE", &acint);
685    if(ACPI_SUCCESS(as)){
686        data.page = acint;
687    } else {
688        ACPI_DEBUG("Could not evaluate PAGE of HPET\n");
689        data.page = 0;
690    }
691
692    as = acpi_eval_integer(handle, "ATTR", &acint);
693    if(ACPI_SUCCESS(as)){
694        data.attr = acint;
695    } else {
696        ACPI_DEBUG("Could not evaluate ATTR of HPET\n");
697        data.attr = 0;
698    }
699
700    as = AcpiWalkResources(handle, METHOD_NAME__CRS, hpet_resource_walker,
701                           &data);
702    if (ACPI_FAILURE(as)) {
703        return as;
704    }
705
706    ACPI_DEBUG("hpet_data uid=%d, base_address=0x%" PRIx64
707             ", page=%d, attr=%d, \n",
708             data.uid, data.base_address, data.page, data.attr);
709
710    skb_add_fact("hpet(%d, %" PRIu64 ", page=%d, attr=%d)",
711             data.uid, data.base_address, data.page, data.attr);
712
713    oct_mset(SET_SEQUENTIAL, HW_HPET_RECORD_FORMAT, data.base_address, data.uid);
714
715    return AE_OK;
716}
717
718
719static int acpi_init(void)
720{
721    AcpiDbgLevel = 0; // ACPI_DEBUG_DEFAULT | ACPI_LV_INFO | ACPI_LV_EXEC;
722
723    // enable workarounds for non-compliant ACPI bytecode
724    AcpiGbl_EnableInterpreterSlack = TRUE;
725
726    ACPI_STATUS as;
727
728    ACPI_DEBUG("Initializing subsystem...\n");
729    as = AcpiInitializeSubsystem();
730    if (ACPI_FAILURE(as)) {
731        ACPI_DEBUG("AcpiInitializeSubsystem failed\n");
732        return as;
733    }
734
735    ACPI_DEBUG("Initializing tables...\n");
736    as = AcpiInitializeTables(NULL, 0, false);
737    if (ACPI_FAILURE(as)) {
738        ACPI_DEBUG("AcpiInitializeTables failed\n");
739        return as;
740    }
741
742    ACPI_DEBUG("Loading tables...\n");
743    as = AcpiLoadTables();
744    if (ACPI_FAILURE(as)) {
745        ACPI_DEBUG("AcpiLoadTables failed %s\n", AcpiFormatException(as));
746        return as;
747    }
748
749    ACPI_DEBUG("Scanning interrupt sources...\n");
750    int r = init_all_interrupt_sources();
751    assert(r == 0);
752
753#ifdef USE_KALUGA_DVM
754    char* record;
755    errval_t err = oct_barrier_enter("barrier.acpi", &record, 2);
756    assert(err_is_ok(err));
757#endif
758
759    ACPI_DEBUG("Enabling full ACPI subsystem...\n");
760    as = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
761    if (ACPI_FAILURE(as)) {
762        ACPI_DEBUG("AcpiEnableSubsystem failed %s\n", AcpiFormatException(as));
763        return as;
764    }
765
766
767    return acpi_arch_init();
768}
769
770/**
771 * \brief Sets system into APIC mode.
772 *
773 * Evaluates _PIC method to argument 1 and disables dual-8259As.
774 * This changes the IRQs reported/set with the interrupt routing (PRT) methods.
775 */
776static ACPI_STATUS set_apic_mode(void)
777{
778    ACPI_OBJECT arg1;
779    ACPI_OBJECT_LIST args;
780    ACPI_STATUS as;
781
782    // Evaluate _PIC method to argument 1
783    arg1.Type = ACPI_TYPE_INTEGER;
784    arg1.Integer.Value = 1;
785    args.Count = 1;
786    args.Pointer = &arg1;
787
788    as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL);
789
790    // Bail out if this didn't work
791    if(ACPI_FAILURE(as)) {
792        return as;
793    }
794
795    return AE_OK;
796}
797
798static void process_srat(ACPI_TABLE_SRAT *srat)
799{
800    ACPI_DEBUG("processing system resource affinity table...\n");
801
802    assert(!strncmp(srat->Header.Signature, "SRAT", ACPI_NAME_SIZE));
803    assert(srat->TableRevision == 1);
804
805    void *pos = (void *)srat + sizeof(ACPI_TABLE_SRAT);
806
807    // Scan subtables
808    while(pos < (void *)srat + srat->Header.Length) {
809        ACPI_SUBTABLE_HEADER *shead = pos;
810
811        switch(shead->Type) {
812        case ACPI_SRAT_TYPE_CPU_AFFINITY:
813            {
814                ACPI_SRAT_CPU_AFFINITY *a = (ACPI_SRAT_CPU_AFFINITY *)shead;
815
816                assert(a->Header.Length == 16);
817
818                if(a->Flags & ACPI_SRAT_MEM_ENABLED) {
819                    uint32_t proximitydomain = (a->ProximityDomainHi[0] << 24) +
820                        (a->ProximityDomainHi[1] << 16) +
821                        (a->ProximityDomainHi[2] << 8) +
822                        a->ProximityDomainLo;
823
824                    ACPI_DEBUG("CPU affinity table:\n");
825                    ACPI_DEBUG("Proximity Domain: %"PRIu32"\n", proximitydomain);
826                    ACPI_DEBUG("CPU local APIC ID: %d\n", a->ApicId);
827                    ACPI_DEBUG("CPU local SAPIC EID: %d\n", a->LocalSapicEid);
828
829                    skb_add_fact("cpu_affinity(%d,%d,%"PRIu32").",
830                        a->ApicId, a->LocalSapicEid, proximitydomain);
831                } else {
832                    ACPI_DEBUG("CPU affinity table disabled!\n");
833                }
834            }
835            break;
836
837        case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
838            {
839                ACPI_SRAT_MEM_AFFINITY *a = (ACPI_SRAT_MEM_AFFINITY *)shead;
840
841                assert(a->Header.Length == 40);
842
843                if(a->Flags & ACPI_SRAT_MEM_ENABLED) {
844                    ACPI_DEBUG("Memory affinity table:\n");
845                    ACPI_DEBUG("Proximity Domain: %"PRIu32"\n", a->ProximityDomain);
846                    ACPI_DEBUG("Base address: 0x%"PRIx64"\n", a->BaseAddress);
847                    ACPI_DEBUG("Length: 0x%"PRIx64"\n", a->Length);
848
849                    bool hotpluggable = false, nonvolatile = false;
850                    if(a->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) {
851                        hotpluggable = true;
852                    }
853                    if(a->Flags & ACPI_SRAT_MEM_NON_VOLATILE) {
854                        nonvolatile = true;
855                    }
856                    ACPI_DEBUG("Flags:%s%s\n",
857                              hotpluggable ? " Hot-pluggable" : "",
858                              nonvolatile ? " Non-volatile" : "");
859
860                    skb_add_fact("memory_affinity(%" PRIu64 ", %" PRIu64 ", %"PRIu32").",
861                        a->BaseAddress, a->Length, a->ProximityDomain);
862
863                } else {
864                    ACPI_DEBUG("Memory affinity table disabled!\n");
865                }
866            }
867            break;
868
869        case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
870            ACPI_DEBUG("Ignoring unsupported x2APIC CPU affinity table.\n");
871
872            break;
873
874        case ACPI_SRAT_TYPE_GICC_AFFINITY:
875            ACPI_DEBUG("Ignoring unsupported GIC CPU affinity table.\n");
876
877            break;
878
879        default:
880            ACPI_DEBUG("Ignoring unknown SRAT subtable ID %d.\n", shead->Type);
881            break;
882        }
883        pos += shead->Length;
884    }
885
886    ACPI_DEBUG("done processing srat...\n");
887}
888
889/**
890 * \brief parses the system locality distance table.
891 *
892 * \param slit  pointer to the SLIT table in memory
893 *
894 * This optional table provides a matrix that describes the relative distance
895 * (memory latency) between all System Localities, which are also referred to as
896 * Proximity Domains
897 */
898static void process_slit(ACPI_TABLE_SLIT *slit)
899{
900    ACPI_DEBUG("processing system locality distance table...\n");
901
902    assert(!strncmp(slit->Header.Signature, ACPI_SIG_SLIT, ACPI_NAME_SIZE));
903    assert(slit->Header.Revision == 1);
904
905    UINT64 locality_count = slit->LocalityCount;
906
907    for (UINT64 i = 0; i < locality_count; ++i) {
908        for (UINT64 j = 0; j < locality_count; ++j) {
909            /*
910             *  The diagonal elements of the matrix, the relative distances from a
911             *  System Locality to itself are normalized to a value of 10. The
912             *  relative distances for the non-diagonal elements are scaled to be
913             *  relative to 10
914             */
915            UINT8 entry = slit->Entry[i*locality_count + j];
916            skb_add_fact("node_distance(%" PRIu64 ", %" PRIu64 ", %"PRIu8").", i,
917                         j, entry);
918            assert(j!=i || entry == 10);
919            ACPI_DEBUG("locality: %lu -> %lu = %u\n", i, j, entry);
920        }
921    }
922
923    ACPI_DEBUG("done processing slit\n");
924}
925
926/**
927 * \brief parses the Memory Topology Table.
928 *
929 * \param slit  pointer to the PMTT table in memory
930 *
931 * This optional table provides a matrix that describes the relative distance
932 * (memory latency) between all System Localities, which are also referred to as
933 * Proximity Domains
934 */
935static void process_pmtt(ACPI_TABLE_PMTT *pmtt)
936{
937    ACPI_DEBUG("processing Platform Memory Topology Table....\n");
938
939    assert(!strncmp(pmtt->Header.Signature, ACPI_SIG_PMTT, ACPI_NAME_SIZE));
940    assert(pmtt->Header.Revision == 1);
941
942    void *pos = (void *)pmtt + sizeof(ACPI_TABLE_PMTT);
943
944    // Scan subtables
945    while(pos < (void *)pmtt + pmtt->Header.Length) {
946
947        ACPI_PMTT_HEADER *shead = pos;
948        switch(shead->Type) {
949            case ACPI_PMTT_TYPE_SOCKET:
950            {
951                ACPI_PMTT_SOCKET *s = (ACPI_PMTT_SOCKET *)shead;
952                debug_printf("ACPI_PMTT_TYPE_SOCKET SocketId=%u\n", s->SocketId);
953
954            }
955                break;
956            case ACPI_PMTT_TYPE_CONTROLLER:
957            {
958                ACPI_PMTT_CONTROLLER *c = (ACPI_PMTT_CONTROLLER *)shead;
959                debug_printf("ACPI_PMTT_TYPE_CONTROLLER DomainCount=%u\n",
960                        c->DomainCount);
961            }
962                break;
963            case ACPI_PMTT_TYPE_DIMM:
964            {
965                ACPI_PMTT_PHYSICAL_COMPONENT *d = (ACPI_PMTT_PHYSICAL_COMPONENT *)shead;
966                debug_printf("ACPI_PMTT_PHYSICAL_COMPONENT MemorySize=%u\n",
967                                        d->MemorySize);
968            }
969
970                break;
971            default:
972                ACPI_DEBUG("WARNING: invalid type %u\n", shead->Type);
973                break;
974        }
975        pos += shead->Length;
976    }
977
978
979    ACPI_DEBUG("done processing pmtt.\n");
980}
981
982
983int init_acpi(void)
984{
985    ACPI_STATUS as;
986
987    ACPI_DEBUG("Initialising ACPI...\n");
988    as = acpi_init();
989    if (ACPI_FAILURE(as)) {
990        printf("ACPI: acpi_init() failed: %s\n", AcpiFormatException(as));
991        return 1;
992    }
993    assert(ACPI_SUCCESS(as));
994
995#if defined(__ARM_ARCH_8A__)
996    // armv8,psci: check if hvc (EL2 call) should be used instead of smc (EL3 call)
997    skb_add_fact("psci_use_hvc(%"PRIu8").", !!(AcpiGbl_FADT.ArmBootFlags & ACPI_FADT_PSCI_USE_HVC));
998#elif defined(__x86__)
999    // Put system into APIC mode
1000    ACPI_DEBUG("Switching to APIC mode...\n");
1001    as = set_apic_mode();
1002    if (ACPI_FAILURE(as)) {
1003        printf("ACPI: Warning: Could not set system to APIC mode! "
1004                  "Continuing anyway... status: %s\n", AcpiFormatException(as));
1005        skb_add_fact("x86_interrupt_model(pic).");
1006    } else {
1007        printf("ACPI: Switched to APIC mode.\n");
1008        skb_add_fact("x86_interrupt_model(apic).");
1009    }
1010#endif
1011
1012    /* look for an MCFG table
1013     * this tells us where the PCI express memory-mapped configuration area is
1014     */
1015
1016    /*
1017    ACPI_TABLE_HEADER *mcfg_header;
1018    as = AcpiGetTable("MCFG", 1, &mcfg_header);
1019    if (ACPI_SUCCESS(as) && mcfg_header->Length >=
1020            sizeof(ACPI_TABLE_MCFG) + sizeof(ACPI_MCFG_ALLOCATION)) {
1021        ACPI_MCFG_ALLOCATION *mcfg = (void *)mcfg_header + sizeof(ACPI_TABLE_MCFG);
1022        ACPI_DEBUG("PCIe enhanced configuration region at 0x%lx "
1023                   "(segment %u, buses %u-%u)\n", mcfg->Address,
1024                   mcfg->PciSegment, mcfg->StartBusNumber, mcfg->EndBusNumber);
1025
1026        skb_add_fact("pcie_confspace(%"PRIu64", %"PRIu16", %"PRIu8", %"PRIu8").",
1027                mcfg->Address, mcfg->PciSegment, mcfg->StartBusNumber,
1028                mcfg->EndBusNumber);
1029
1030        //XXX: Not needed as long as PCIe walking is disabled
1031        r = pcie_confspace_init(mcfg->Address, mcfg->PciSegment,
1032                                mcfg->StartBusNumber, mcfg->EndBusNumber);
1033        if (r == 0) {
1034            // XXX: compute physical address region used by conf space
1035            struct memrange confspace = {
1036                .min = mcfg->Address,
1037                .limit = mcfg->Address +
1038               ((lpaddr_t)(mcfg->EndBusNumber + 1 - mcfg->StartBusNumber) << 20)
1039            };
1040            reserved_memory[n_reserved_memory_regions++] = confspace;
1041        }
1042
1043    } else {
1044        ACPI_DEBUG("No MCFG table found -> no PCIe enhanced configuration\n");
1045    }*/
1046
1047    // XXX: disable PCIe memory-mapped config space until after we walk and
1048    // prescan all the buses. This is necessary on some AMD boxes, because the
1049    // ACPI table includes code to read registers in the HyperTransport config,
1050    // and this only appears in IO space.
1051    // We need a cleaner way of determining when to use PCIe config space!
1052    pcie_disable();
1053
1054    /* Find and reserve all memory regions claimed by non-PCI devices */
1055    ACPI_DEBUG("Reserving fixed resources\n");
1056    as = AcpiGetDevices("PNP0C02", reserve_resources, NULL, NULL);
1057    if (ACPI_FAILURE(as) && as != AE_NOT_FOUND) {
1058        printf("WARNING: AcpiGetDevices (fixed resources) failed with error %"PRIu32"\n", as);
1059    }
1060    assert(ACPI_SUCCESS(as) || as == AE_NOT_FOUND);
1061
1062    /* Find HPETs */
1063    ACPI_DEBUG("Scanning for HPET");
1064    as = AcpiGetDevices(HPET_HID_STRING, add_hpet_device, NULL, NULL);
1065    if (ACPI_FAILURE(as) && as != AE_NOT_FOUND) {
1066        printf("WARNING: AcpiGetDevices (hpet) failed with error %"PRIu32"\n", as);
1067    }
1068    assert(ACPI_SUCCESS(as) || as == AE_NOT_FOUND);
1069
1070
1071
1072
1073
1074    // XXX: PCIe walking disabled, as these also show up as PCI buses,
1075    // and we don't currently distinguish between them
1076    //ACPI_DEBUG("Walking for PCIe buses\n");
1077    //as = AcpiGetDevices(PCI_EXPRESS_ROOT_HID_STRING, add_pci_device, NULL, NULL);
1078    //assert(ACPI_SUCCESS(as));
1079
1080    acpi_parse_dmar();
1081
1082    ACPI_DEBUG("Walking for PCI buses\n");
1083    as = AcpiGetDevices(PCI_ROOT_HID_STRING, add_pci_device, NULL, NULL);
1084    assert(ACPI_SUCCESS(as));
1085
1086    ACPI_DEBUG("Walking for PCI Link devices\n");
1087    as = AcpiGetDevices(PCI_LNK_DEV_STRING, add_pci_lnk_device, NULL, NULL);
1088    assert(ACPI_SUCCESS(as));
1089
1090    //ACPI_DEBUG("Programming PCI BARs and bridge windows\n");
1091    //pci_program_bridges();
1092    //ACPI_DEBUG("PCI programming completed\n");
1093
1094    ACPI_TABLE_HEADER *acpi_table_header;
1095
1096    as = AcpiGetTable(ACPI_SIG_SRAT, 1, &acpi_table_header);
1097    ACPI_DEBUG("has SRAT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1098    if(ACPI_SUCCESS(as)) {
1099        process_srat((ACPI_TABLE_SRAT *)acpi_table_header);
1100    }
1101
1102    /*
1103     * try to parse the SLIT. This is an optional table
1104     */
1105    as = AcpiGetTable(ACPI_SIG_SLIT, 1, &acpi_table_header);
1106    ACPI_DEBUG("has SLIT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1107    if(ACPI_SUCCESS(as)) {
1108        process_slit((ACPI_TABLE_SLIT *)acpi_table_header);
1109    }
1110
1111    /*
1112     * try to parse the PMTT. This is an optional table
1113     */
1114    as = AcpiGetTable(ACPI_SIG_PMTT, 1, &acpi_table_header);
1115    ACPI_DEBUG("has PMTT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1116    if(ACPI_SUCCESS(as)) {
1117        process_pmtt((ACPI_TABLE_PMTT *)acpi_table_header);
1118    }
1119
1120    /*
1121     * try to parse the PSDT. This is an optional table
1122     */
1123    as = AcpiGetTable(ACPI_SIG_PSDT, 1, &acpi_table_header);
1124    ACPI_DEBUG("has PSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1125
1126    /*
1127     * try to parse the RSDT. This is an optional table
1128     */
1129    as = AcpiGetTable(ACPI_SIG_RSDT, 1, &acpi_table_header);
1130    ACPI_DEBUG("has RSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1131
1132    /*
1133     * try to parse the SSDT. This is an optional table
1134     */
1135    as = AcpiGetTable(ACPI_SIG_SSDT, 1, &acpi_table_header);
1136    ACPI_DEBUG("has SSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1137
1138    /*
1139     * try to parse the XSDT. This is an optional table
1140     */
1141    as = AcpiGetTable(ACPI_SIG_XSDT, 1, &acpi_table_header);
1142    ACPI_DEBUG("has XSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no");
1143
1144    return 0;
1145}
1146