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