1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 #include <acpica/acpi.h>
6 #include <acpica/actypes.h>
7 #include <acpica/acuuid.h>
8 #include <bits/limits.h>
9 #include <ddk/debug.h>
10 #include <fbl/alloc_checker.h>
11 #include <fbl/unique_ptr.h>
12 #include <fbl/vector.h>
13 #include <inttypes.h>
14 #include <region-alloc/region-alloc.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "acpi-private.h"
19 #include "methods.h"
20 #include "pci.h"
21 #include "pciroot.h"
22 #include "resources.h"
23 
24 // This file contains the implementation for the code supporting the in-progress userland
25 // pci bus driver.
26 
27 static fbl::Vector<pci_mcfg_allocation_t*> mcfg_allocations;
28 const char* kLogTag = "acpi-pci:";
29 
30 // These allocators container available regions of physical address space in the memory
31 // map that we should be able to allocate bars from. Different allocators exist for 32
32 // and 64 bit bars so that we can be sure addresses at < 4GB are preserved for 32 bit
33 // bars.
34 RegionAllocator kMmio32Alloc;
35 RegionAllocator kMmio64Alloc;
36 RegionAllocator kIoAlloc;
37 
38 struct report_current_resources_ctx {
39     zx_handle_t pci_handle;
40     bool device_is_root_bridge;
41     bool add_pass;
42 };
43 
report_current_resources_resource_cb_ex(ACPI_RESOURCE * res,void * _ctx)44 static ACPI_STATUS report_current_resources_resource_cb_ex(ACPI_RESOURCE* res, void* _ctx) {
45     auto* ctx = static_cast<struct report_current_resources_ctx*>(_ctx);
46     zx_status_t status;
47 
48     bool is_mmio = false;
49     uint64_t base = 0;
50     uint64_t len = 0;
51     bool add_range = false;
52 
53     if (resource_is_memory(res)) {
54         resource_memory_t mem;
55         status = resource_parse_memory(res, &mem);
56         if (status != ZX_OK || mem.minimum != mem.maximum) {
57             return AE_ERROR;
58         }
59 
60         is_mmio = true;
61         base = mem.minimum;
62         len = mem.address_length;
63     } else if (resource_is_address(res)) {
64         resource_address_t addr;
65         status = resource_parse_address(res, &addr);
66         if (status != ZX_OK) {
67             return AE_ERROR;
68         }
69 
70         if (addr.resource_type == RESOURCE_ADDRESS_MEMORY) {
71             is_mmio = true;
72         } else if (addr.resource_type == RESOURCE_ADDRESS_IO) {
73             is_mmio = false;
74         } else {
75             return AE_OK;
76         }
77 
78         if (!addr.min_address_fixed || !addr.max_address_fixed || addr.maximum < addr.minimum) {
79             printf("WARNING: ACPI found bad _CRS address entry\n");
80             return AE_OK;
81         }
82 
83         // We compute len from maximum rather than address_length, since some
84         // implementations don't set address_length...
85         base = addr.minimum;
86         len = addr.maximum - base + 1;
87 
88         // PCI root bridges report downstream resources via _CRS.  Since we're
89         // gathering data on acceptable ranges for PCI to use for MMIO, consider
90         // non-consume-only address resources to be valid for PCI MMIO.
91         if (ctx->device_is_root_bridge && !addr.consumed_only) {
92             add_range = true;
93         }
94     } else if (resource_is_io(res)) {
95         resource_io_t io;
96         status = resource_parse_io(res, &io);
97         if (status != ZX_OK) {
98             return AE_ERROR;
99         }
100 
101         if (io.minimum != io.maximum) {
102             printf("WARNING: ACPI found bad _CRS IO entry\n");
103             return AE_OK;
104         }
105 
106         is_mmio = false;
107         base = io.minimum;
108         len = io.address_length;
109     } else {
110         return AE_OK;
111     }
112 
113     // Ignore empty regions that are reported, and skip any resources that
114     // aren't for the pass we're doing.
115     if (len == 0 || add_range != ctx->add_pass) {
116         return AE_OK;
117     }
118 
119     if (add_range && is_mmio && base < 1024 * 1024) {
120         // The PC platform defines many legacy regions below 1MB that we do not
121         // want PCIe to try to map onto.
122         zxlogf(INFO, "Skipping adding MMIO range, due to being below 1MB\n");
123         return AE_OK;
124     }
125 
126     // Add/Subtract the [base, len] region we found through ACPI to the allocators
127     // that PCI can use to allocate BARs.
128     RegionAllocator* alloc;
129     if (is_mmio) {
130         if (base + len < UINT32_MAX) {
131             alloc = &kMmio32Alloc;
132         } else {
133             alloc = &kMmio64Alloc;
134         }
135     } else {
136         alloc = &kIoAlloc;
137     }
138 
139     zxlogf(TRACE, "ACPI range modification: %sing %s %016lx %016lx\n",
140            add_range ? "add" : "subtract", is_mmio ? "MMIO" : "PIO", base, len);
141     if (add_range) {
142         status = alloc->AddRegion({.base = base, .size = len}, true);
143     } else {
144         status = alloc->SubtractRegion({.base = base, .size = len}, true);
145     }
146 
147     if (status != ZX_OK) {
148         if (add_range) {
149             zxlogf(INFO, "Failed to add range: %d\n", status);
150         } else {
151             // If we are subtracting a range and fail, abort.  This is bad.
152             return AE_ERROR;
153         }
154     }
155     return AE_OK;
156 }
157 
report_current_resources_device_cb_ex(ACPI_HANDLE object,uint32_t nesting_level,void * _ctx,void ** ret)158 static ACPI_STATUS report_current_resources_device_cb_ex(
159     ACPI_HANDLE object, uint32_t nesting_level, void* _ctx, void** ret) {
160 
161     ACPI_DEVICE_INFO* info = NULL;
162     ACPI_STATUS status = AcpiGetObjectInfo(object, &info);
163     if (status != AE_OK) {
164         return status;
165     }
166 
167     auto* ctx = static_cast<struct report_current_resources_ctx*>(_ctx);
168     ctx->device_is_root_bridge = (info->Flags & ACPI_PCI_ROOT_BRIDGE) != 0;
169 
170     ACPI_FREE(info);
171 
172     status = AcpiWalkResources(object, (char*)"_CRS", report_current_resources_resource_cb_ex, ctx);
173     if (status == AE_NOT_FOUND || status == AE_OK) {
174         return AE_OK;
175     }
176     return status;
177 }
178 
179 /* @brief Report current resources to the kernel PCI driver
180  *
181  * Walks the ACPI namespace and use the reported current resources to inform
182    the kernel PCI interface about what memory it shouldn't use.
183  *
184  * @param root_resource_handle The handle to pass to the kernel when talking
185  * to the PCI driver.
186  *
187  * @return ZX_OK on success
188  */
pci_report_current_resources_ex(zx_handle_t root_resource_handle)189 zx_status_t pci_report_current_resources_ex(zx_handle_t root_resource_handle) {
190     // First we search for resources to add, then we subtract out things that
191     // are being consumed elsewhere.  This forces an ordering on the
192     // operations so that it should be consistent, and should protect against
193     // inconistencies in the _CRS methods.
194 
195     // Walk the device tree and add to the PCIe IO ranges any resources
196     // "produced" by the PCI root in the ACPI namespace.
197     struct report_current_resources_ctx ctx = {
198         .pci_handle = root_resource_handle,
199         .device_is_root_bridge = false,
200         .add_pass = true,
201     };
202     ACPI_STATUS status = AcpiGetDevices(NULL, report_current_resources_device_cb_ex, &ctx, NULL);
203     if (status != AE_OK) {
204         return ZX_ERR_INTERNAL;
205     }
206 
207     // Removes resources we believe are in use by other parts of the platform
208     ctx = (struct report_current_resources_ctx){
209         .pci_handle = root_resource_handle,
210         .device_is_root_bridge = false,
211         .add_pass = false,
212     };
213     status = AcpiGetDevices(NULL, report_current_resources_device_cb_ex, &ctx, NULL);
214     if (status != AE_OK) {
215         return ZX_ERR_INTERNAL;
216     }
217 
218     return ZX_OK;
219 }
220 
221 // Reads the MCFG table from ACPI and caches it for later calls
222 // to pci_ger_segment_mcfg_alloc()
pci_read_mcfg_table(void)223 static zx_status_t pci_read_mcfg_table(void) {
224     // Systems will have an MCFG table unless they only support legacy PCI.
225     ACPI_TABLE_HEADER* raw_table = NULL;
226     ACPI_STATUS status = AcpiGetTable(const_cast<char*>(ACPI_SIG_MCFG), 1, &raw_table);
227     if (status != AE_OK) {
228         zxlogf(TRACE, "%s no MCFG table found.\n", kLogTag);
229         return ZX_ERR_NOT_FOUND;
230     }
231 
232     // The MCFG table contains a variable number of Extended Config tables
233     // hanging off of the end.  Typically there will be one, but more
234     // complicated systems may have multiple per PCI Host Bridge. The length in
235     // the header is the overall size, so that is used to calculate how many
236     // ECAMs are included.
237     ACPI_TABLE_MCFG* mcfg = reinterpret_cast<ACPI_TABLE_MCFG*>(raw_table);
238     uintptr_t table_start = reinterpret_cast<uintptr_t>(mcfg) + sizeof(ACPI_TABLE_MCFG);
239     uintptr_t table_end = reinterpret_cast<uintptr_t>(mcfg) + mcfg->Header.Length;
240     size_t table_bytes = table_end - table_start;
241     if (table_bytes % sizeof(pci_mcfg_allocation_t)) {
242         zxlogf(ERROR, "%s MCFG table has invalid size %zu\n", kLogTag, table_bytes);
243         return ZX_ERR_INTERNAL;
244     }
245 
246     // Each allocation corresponds to a particular PCI Segment Group. We'll
247     // store them so that the protocol can return them for bus driver instances
248     // later.
249     for (unsigned i = 0; i < table_bytes / sizeof(pci_mcfg_allocation_t); i++) {
250         auto entry = &(reinterpret_cast<pci_mcfg_allocation_t*>(table_start))[i];
251         mcfg_allocations.push_back(entry);
252         zxlogf(TRACE, "%s MCFG allocation %u (Addr = %#lx, Segment = %u, Start = %u, End = %u)\n",
253                kLogTag, i, entry->base_address, entry->segment_group, entry->start_bus_num,
254                entry->end_bus_num);
255     }
256     return ZX_OK;
257 }
258 
pci_platform_has_mcfg(void)259 bool pci_platform_has_mcfg(void) {
260     return (mcfg_allocations.size() != 0);
261 }
262 
263 // Search the MCFG allocations found earlier for an entry matching a given
264 // segment a host bridge is a part of. Per the PCI Firmware spec v3 table 4-3
265 // note 1, a given segment group will contain only a single mcfg allocation
266 // entry.
pci_get_segment_mcfg_alloc(unsigned segment_group,pci_mcfg_allocation_t * out)267 zx_status_t pci_get_segment_mcfg_alloc(unsigned segment_group, pci_mcfg_allocation_t* out) {
268     for (auto& entry : mcfg_allocations) {
269         if (entry->segment_group == segment_group) {
270             *out = *entry;
271             return ZX_OK;
272         }
273     }
274     return ZX_ERR_NOT_FOUND;
275 }
276 
277 static zx_protocol_device_t pciroot_device_ops = {
278     .version = DEVICE_OPS_VERSION,
279     .get_protocol = nullptr,
280     .open = nullptr,
281     .open_at = nullptr,
282     .close = nullptr,
283     .unbind = nullptr,
284     .release = nullptr,
285     .read = nullptr,
286     .write = nullptr,
287     .get_size = nullptr,
288     .ioctl = nullptr,
289     .suspend = nullptr,
290     .resume = nullptr,
291     .rxrpc = nullptr,
292     .message = nullptr,
293 };
294 
pci_init_bookkeeping(void)295 zx_status_t pci_init_bookkeeping(void) {
296     zx_status_t status;
297     auto region_pool = RegionAllocator::RegionPool::Create(PAGE_SIZE);
298     if (region_pool == nullptr) {
299         return ZX_ERR_NO_MEMORY;
300     }
301 
302     status = kMmio32Alloc.SetRegionPool(region_pool);
303     if (status != ZX_OK) {
304         return status;
305     }
306 
307     status = kMmio64Alloc.SetRegionPool(region_pool);
308     if (status != ZX_OK) {
309         return status;
310     }
311 
312     status = kIoAlloc.SetRegionPool(region_pool);
313     if (status != ZX_OK) {
314         return status;
315     }
316 
317     // MCFG table will only exist with PCIe so 'not found' is not a failure case.
318     status = pci_read_mcfg_table();
319     if (status != ZX_OK && status != ZX_ERR_NOT_FOUND) {
320         zxlogf(ERROR, "%s error attempting to read mcfg table %d\n", kLogTag, status);
321         return status;
322     }
323 
324     status = pci_report_current_resources_ex(get_root_resource());
325     if (status != ZX_OK) {
326         zxlogf(ERROR, "%s error attempting to populate PCI allocators %d\n", kLogTag, status);
327         return status;
328     }
329 
330     return ZX_OK;
331 }
332 
pci_init(zx_device_t * parent,ACPI_HANDLE object,ACPI_DEVICE_INFO * info,publish_acpi_device_ctx_t * ctx)333 zx_status_t pci_init(zx_device_t* parent,
334                      ACPI_HANDLE object,
335                      ACPI_DEVICE_INFO* info,
336                      publish_acpi_device_ctx_t* ctx) {
337     static bool pci_bookkeeping_initialized = false;
338     zx_status_t status = ZX_OK;
339 
340     // If it's the first time we've found a root we need to set up our address
341     // space allocators and walk the various ACPI tables.
342     if (!pci_bookkeeping_initialized) {
343         status = pci_init_bookkeeping();
344         if (status != ZX_OK) {
345             return status;
346         }
347         pci_bookkeeping_initialized = true;
348     }
349 
350     // Build up a context structure for the PCI Root / Host Bridge we've found.
351     // If we find _BBN / _SEG we will use those, but if we don't we can fall
352     // back on having an ecam from mcfg allocations.
353     fbl::AllocChecker ac;
354     auto dev_ctx = fbl::unique_ptr<pciroot_ctx_t>(new (&ac) pciroot_ctx_t());
355     if (!ac.check()) {
356         zxlogf(ERROR, "failed to allocate pciroot ctx: %d!\n", status);
357         return ZX_ERR_NO_MEMORY;
358     }
359 
360     dev_ctx->acpi_object = object;
361     dev_ctx->acpi_device_info = *info;
362     // ACPI names are stored as 4 bytes in a u32
363     memcpy(dev_ctx->name, &info->Name, 4);
364 
365     status = acpi_bbn_call(object, &dev_ctx->info.start_bus_num);
366     if (status != ZX_OK && status != ZX_ERR_NOT_FOUND) {
367         zxlogf(TRACE, "%s Unable to read _BBN for '%s' (%d), assuming base bus of 0\n",
368                kLogTag, dev_ctx->name, status);
369 
370         // Until we find an ecam we assume this potential legacy pci bus spans
371         // bus 0 to bus 255 in its segment group.
372         dev_ctx->info.end_bus_num = 255;
373     }
374     bool found_bbn = (status == ZX_OK);
375 
376     status = acpi_seg_call(object, &dev_ctx->info.segment_group);
377     if (status != ZX_OK) {
378         dev_ctx->info.segment_group = 0;
379         zxlogf(TRACE, "%s Unable to read _SEG for '%s' (%d), assuming segment group 0.\n",
380                kLogTag, dev_ctx->name, status);
381     }
382 
383     // If an MCFG is found for the given segment group this root has then we'll
384     // cache it for later pciroot operations and use its information to populate
385     // any fields missing via _BBN / _SEG.
386     auto& pinfo = dev_ctx->info;
387     pci_mcfg_allocation_t mcfg_alloc;
388     status = pci_get_segment_mcfg_alloc(dev_ctx->info.segment_group, &mcfg_alloc);
389     if (status == ZX_OK) {
390         // Do the bus values make sense?
391         if (found_bbn && mcfg_alloc.start_bus_num != pinfo.start_bus_num) {
392             zxlogf(ERROR,
393                    "%s: conflicting base bus num for '%s', _BBN reports %u and MCFG reports %u\n",
394                    kLogTag, dev_ctx->name, pinfo.start_bus_num, mcfg_alloc.start_bus_num);
395         }
396 
397         // Do the segment values make sense?
398         if (pinfo.segment_group != 0 && pinfo.segment_group != mcfg_alloc.segment_group) {
399             zxlogf(ERROR,
400                    "%s: conflicting segment group for '%s', _BBN reports %u and MCFG reports %u\n",
401                    kLogTag, dev_ctx->name, pinfo.segment_group, mcfg_alloc.segment_group);
402         }
403 
404         // Since we have an ecam its metadata will replace anything defined in the ACPI tables.
405         pinfo.segment_group = mcfg_alloc.segment_group;
406         pinfo.start_bus_num = mcfg_alloc.start_bus_num;
407         pinfo.end_bus_num = mcfg_alloc.end_bus_num;
408 
409         // The bus driver needs a VMO representing the entire ecam region so it can map it in.
410         // The range from start_bus_num to end_bus_num is inclusive.
411         size_t ecam_size = (pinfo.end_bus_num - pinfo.start_bus_num + 1) * PCIE_ECAM_BYTES_PER_BUS;
412         zx_paddr_t vmo_base = mcfg_alloc.base_address +
413                               (pinfo.start_bus_num * PCIE_ECAM_BYTES_PER_BUS);
414         status = zx_vmo_create_physical(get_root_resource(), vmo_base, ecam_size, &pinfo.ecam_vmo);
415         if (status != ZX_OK) {
416             zxlogf(ERROR, "couldn't create VMO for ecam, mmio cfg will not work: %d!\n", status);
417             return status;
418         }
419     }
420 
421     if (zxlog_level_enabled(TRACE)) {
422         printf("%s %s { acpi_obj(%p), bus range: %u:%u, segment: %u }\n", kLogTag,
423                dev_ctx->name, dev_ctx->acpi_object, pinfo.start_bus_num, pinfo.end_bus_num,
424                pinfo.segment_group);
425         if (pinfo.ecam_vmo != ZX_HANDLE_INVALID) {
426             printf("%s ecam base %#" PRIxPTR "\n", kLogTag, mcfg_alloc.base_address);
427         }
428     }
429 
430     device_add_args_t args = {
431         .version = DEVICE_ADD_ARGS_VERSION,
432         .name = dev_ctx->name,
433         .ctx = dev_ctx.get(),
434         .ops = &pciroot_device_ops,
435         .props = nullptr,
436         .prop_count = 0,
437         .proto_id = ZX_PROTOCOL_PCIROOT,
438         .proto_ops = get_pciroot_ops(),
439         .proxy_args = nullptr,
440         .flags = 0,
441     };
442 
443     // These are cached here to work around dev_ctx potentially going out of scope
444     // after device_add in the event that unbind/release are called from the DDK. See
445     // the below TODO for more information.
446     char name[5];
447     uint8_t last_pci_bbn = dev_ctx->info.start_bus_num;
448     memcpy(name, dev_ctx->name, sizeof(name));
449 
450     status = device_add(parent, &args, &dev_ctx->zxdev);
451     if (status != ZX_OK) {
452         zxlogf(ERROR, "%s failed to add pciroot device for '%s': %d\n",
453                kLogTag, dev_ctx->name, status);
454     } else {
455         // devmgr owns the ctx pointer now so release it from the uptr
456         __UNUSED auto p = dev_ctx.release();
457 
458         // TODO(cja): these support the legacy-ish ACPI nhlt table handling that will need to be
459         // updated in the future.
460         ctx->found_pci = true;
461         ctx->last_pci = last_pci_bbn;
462         zxlogf(INFO, "%s published pciroot '%s'\n", kLogTag, name);
463     }
464 
465     return status;
466 }
467