6#if (X86 || X64) && MULTIPROCESSOR && ACPI
7#include "pedigree/kernel/LockGuard.h"
8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/machine/Device.h"
10#include "pedigree/kernel/process/Mutex.h"
11#include "pedigree/kernel/utilities/Vector.h"
13#include "system/kernel/machine/mach_pc/Acpi.h"
14#include "system/kernel/machine/mach_pc/Pic.h"
15#include <uacpi/acpi.h>
16#include <uacpi/resources.h>
17#include <uacpi/uacpi.h>
18#include <uacpi/utilities.h>
22 uacpi_namespace_node* node;
28 uacpi_namespace_node* node;
39struct ResourceLookup {
42 uacpi_resource* found =
nullptr;
43 bool dependent =
false;
46uacpi_iteration_decision findResource(
void* user, uacpi_resource* resource) {
47 auto& lookup = *
static_cast<ResourceLookup*
>(user);
48 if (resource->type == UACPI_RESOURCE_TYPE_START_DEPENDENT ||
49 resource->type == UACPI_RESOURCE_TYPE_END_DEPENDENT) {
50 lookup.dependent =
true;
52 if (resource->type != UACPI_RESOURCE_TYPE_END_TAG) {
53 if (lookup.index == lookup.wanted) {
54 lookup.found = resource;
58 return UACPI_ITERATION_DECISION_CONTINUE;
61bool interruptResource(uacpi_resource* resource,
size_t& count,
bool& activeLow) {
65 uint8_t trigger = 0, polarity = 0, sharing = 0;
66 if (resource->type == UACPI_RESOURCE_TYPE_IRQ) {
67 const auto& irq = resource->irq;
69 trigger = irq.triggering;
70 polarity = irq.polarity;
71 sharing = irq.sharing;
72 }
else if (resource->type == UACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
73 const auto& irq = resource->extended_irq;
74 if (irq.direction != UACPI_CONSUMER || irq.source.length) {
78 trigger = irq.triggering;
79 polarity = irq.polarity;
80 sharing = irq.sharing;
84 activeLow = polarity == UACPI_POLARITY_ACTIVE_LOW;
85 return trigger == UACPI_TRIGGERING_LEVEL && polarity <= UACPI_POLARITY_ACTIVE_LOW &&
86 sharing == UACPI_SHARED;
89uint32_t interruptNumber(uacpi_resource* resource,
size_t index) {
90 return resource->type == UACPI_RESOURCE_TYPE_IRQ ? resource->irq.irqs[index]
91 : resource->extended_irq.irqs[index];
95 uacpi_resources* resources =
nullptr;
96 if (uacpi_get_current_resources(node, &resources) != UACPI_STATUS_OK || !resources) {
99 ResourceLookup lookup{index};
101 const bool valid = uacpi_for_each_resource(resources, findResource, &lookup) == UACPI_STATUS_OK &&
102 !lookup.dependent && interruptResource(lookup.found, count, route.activeLow) &&
105 route.gsi = interruptNumber(lookup.found, 0);
107 uacpi_free_resources(resources);
112 for (
const Link& link : g_Links) {
113 if (link.node == node && link.index == index) {
119 if (uacpi_eval_sta(node, &status) != UACPI_STATUS_OK ||
120 !(status & ACPI_STA_RESULT_DEVICE_PRESENT)) {
123 if (status & ACPI_STA_RESULT_DEVICE_ENABLED) {
124 if (!readCurrent(node, index, route) ||
125 !
Pic::instance().reservePciGsi(route.gsi, route.activeLow)) {
128 g_Links.
pushBack({node, index, route,
true});
134 uacpi_resources* possible =
nullptr;
135 if (index || uacpi_get_possible_resources(node, &possible) != UACPI_STATUS_OK || !possible) {
138 uacpi_resources* previous =
nullptr;
139 ResourceLookup previousLookup{0};
140 if (uacpi_get_current_resources(node, &previous) != UACPI_STATUS_OK || !previous ||
141 uacpi_for_each_resource(previous, findResource, &previousLookup) != UACPI_STATUS_OK ||
142 previousLookup.dependent || previousLookup.index != 1) {
143 uacpi_free_resources(previous);
144 uacpi_free_resources(possible);
147 ResourceLookup lookup{0};
149 bool selected =
false;
150 if (uacpi_for_each_resource(possible, findResource, &lookup) == UACPI_STATUS_OK &&
151 !lookup.dependent && lookup.index == 1 && lookup.found->type == previousLookup.found->type &&
152 (lookup.found->type == UACPI_RESOURCE_TYPE_IRQ
153 ? previousLookup.found->irq.length_kind == UACPI_RESOURCE_LENGTH_KIND_FULL
154 : lookup.found->type == UACPI_RESOURCE_TYPE_EXTENDED_IRQ &&
155 previousLookup.found->extended_irq.num_irqs == 1 &&
156 !previousLookup.found->extended_irq.source.length) &&
157 interruptResource(lookup.found, count, route.activeLow)) {
158 for (
size_t i = 0; i < count; ++i) {
159 route.gsi = interruptNumber(lookup.found, i);
160 if (
Pic::instance().reservePciGsi(route.gsi, route.activeLow)) {
167 uacpi_free_resources(previous);
168 uacpi_free_resources(possible);
172 if (lookup.found->type == UACPI_RESOURCE_TYPE_IRQ) {
173 lookup.found->irq.length_kind = previousLookup.found->irq.length_kind;
174 lookup.found->irq.num_irqs = 1;
175 lookup.found->irq.irqs[0] = route.gsi;
177 lookup.found->extended_irq.num_irqs = 1;
178 lookup.found->extended_irq.irqs[0] = route.gsi;
180 uacpi_free_resources(previous);
184 const size_t slot = g_Links.
size();
185 g_Links.
pushBack({node, index, route,
false});
186 const uacpi_status result = uacpi_set_resources(node, possible);
187 uacpi_free_resources(possible);
189 if (result != UACPI_STATUS_OK || uacpi_eval_sta(node, &status) != UACPI_STATUS_OK ||
190 !(status & ACPI_STA_RESULT_DEVICE_PRESENT) || !(status & ACPI_STA_RESULT_DEVICE_ENABLED) ||
191 !readCurrent(node, index, current) || current.gsi != route.gsi ||
192 current.activeLow != route.activeLow) {
193 WARNING(
"PCI INTx: interrupt-link configuration could not be verified");
196 g_Links[slot].valid =
true;
197 NOTICE(
"PCI INTx: configured ACPI interrupt link on GSI " <<
Dec << route.gsi);
203 uacpi_namespace_node* node =
nullptr;
207uacpi_iteration_decision findChild(
void* user, uacpi_namespace_node* node, uacpi_u32) {
208 auto& lookup = *
static_cast<ChildLookup*
>(user);
209 uint64_t address = 0;
210 const auto status = uacpi_eval_simple_integer(node,
"_ADR", &address);
211 if (status == UACPI_STATUS_OK && address == lookup.address) {
213 lookup.valid =
false;
214 return UACPI_ITERATION_DECISION_BREAK;
218 return UACPI_ITERATION_DECISION_CONTINUE;
226 const Root* root =
nullptr;
227 for (
const Root& candidate : g_Roots) {
228 if (device->getPciBusPosition() >= candidate.firstBus &&
229 device->getPciBusPosition() <= candidate.lastBus) {
245 current = bus ? bus->
getParent() :
nullptr;
247 path.
size() == 256) {
253 uacpi_namespace_node* scope = root->node;
255 for (
size_t i = path.
size(); i > 1; --i) {
257 Device* bridge = path[i - 1];
260 if (uacpi_namespace_for_each_child(scope, findChild,
nullptr, UACPI_OBJECT_DEVICE_BIT, 1,
261 &lookup) != UACPI_STATUS_OK ||
270 for (
size_t level = 0; level < path.
size(); ++level) {
271 current = path[level];
272 scope = scopes[path.
size() - 1 - level];
273 uacpi_pci_routing_table* table =
nullptr;
274 const uacpi_status result =
275 scope ? uacpi_get_pci_routing_table(scope, &table) : UACPI_STATUS_NOT_FOUND;
276 if (result == UACPI_STATUS_OK && table) {
277 const uacpi_pci_routing_table_entry* match =
nullptr;
279 for (
size_t i = 0; i < table->num_entries; ++i) {
280 const auto& entry = table->entries[i];
281 const uint32_t slot = entry.address >> 16;
282 const uint32_t function = entry.address & 0xffff;
283 if (entry.pin > 3 || slot > 31 || (function > 7 && function != 0xffff)) {
296 valid = valid && match;
299 valid = resolveLink(match->source, match->index, route);
301 route = {match->index,
true};
302 valid =
Pic::instance().reservePciGsi(route.gsi, route.activeLow);
305 uacpi_free_pci_routing_table(table);
308 if (result != UACPI_STATUS_NOT_FOUND) {
317void addPciRoutingRoot(uacpi_namespace_node* node, uint8_t firstBus, uint8_t lastBus) {
318 g_Roots.
pushBack({node, firstBus, lastBus});
321void initialisePciRouting() {
326 Acpi::instance().setPciInterruptRouter(routeInterrupt);
327 if (uacpi_set_interrupt_model(UACPI_INTERRUPT_MODEL_IOAPIC) != UACPI_STATUS_OK) {
328 WARNING(
"PCI INTx: firmware could not select APIC routing");
332 NOTICE(
"PCI INTx: AML routing enabled in APIC mode");
335void addPciRoutingRoot(uacpi_namespace_node*, uint8_t, uint8_t) {}
336void initialisePciRouting() {}
uint32_t getPciFunctionNumber()
uint32_t getPciDevicePosition()
uint8_t getPciClassCode()
uint8_t getPciSubclassCode()
Device * getParent() const
uint32_t getPciBusPosition()
A vector / dynamic array.
void pushBack(const T &value)