1 /*
2 * The PCI Library -- Direct Configuration access via PCIe ECAM
3 *
4 * Copyright (c) 2023 Pali Rohár <[email protected]>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "internal.h"
12 #include "physmem.h"
13 #include "physmem-access.h"
14
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <limits.h>
21
22 #ifndef PCI_OS_WINDOWS
23 #include <glob.h>
24 #include <unistd.h>
25 #endif
26
27 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
28 #include <sys/sysctl.h>
29 #endif
30
31 #if defined (__FreeBSD__) || defined (__DragonFly__)
32 #include <kenv.h>
33 #endif
34
35 #ifdef _WIN32
36 #include "win32-helpers.h"
37 #endif
38
39 struct acpi_rsdp {
40 char signature[8];
41 u8 checksum;
42 char oem_id[6];
43 u8 revision;
44 u32 rsdt_address;
45 struct {
46 u32 length;
47 u64 xsdt_address;
48 u8 ext_checksum;
49 u8 reserved[3];
50 } rsdp20[0];
51 } PCI_PACKED;
52
53 struct acpi_sdt {
54 char signature[4];
55 u32 length;
56 u8 revision;
57 u8 checksum;
58 char oem_id[6];
59 char oem_table_id[8];
60 u32 oem_revision;
61 char asl_compiler_id[4];
62 u32 asl_compiler_revision;
63 } PCI_PACKED;
64
65 struct acpi_rsdt {
66 struct acpi_sdt sdt;
67 u32 sdt_addresses[0];
68 } PCI_PACKED;
69
70 struct acpi_xsdt {
71 struct acpi_sdt sdt;
72 u64 sdt_addresses[0];
73 } PCI_PACKED;
74
75 struct acpi_mcfg {
76 struct acpi_sdt sdt;
77 u64 reserved;
78 struct {
79 u64 address;
80 u16 pci_segment;
81 u8 start_bus_number;
82 u8 end_bus_number;
83 u32 reserved;
84 } allocations[0];
85 } PCI_PACKED;
86
87 struct mmap_cache {
88 void *map;
89 u64 addr;
90 u32 length;
91 int domain;
92 u8 bus;
93 int w;
94 };
95
96 // Back-end data linked to struct pci_access
97 struct ecam_access {
98 struct acpi_mcfg *mcfg;
99 struct mmap_cache *cache;
100 struct physmem *physmem;
101 long pagesize;
102 };
103
104 static unsigned int
get_rsdt_addresses_count(struct acpi_rsdt * rsdt)105 get_rsdt_addresses_count(struct acpi_rsdt *rsdt)
106 {
107 return (rsdt->sdt.length - ((unsigned char*)&rsdt->sdt_addresses - (unsigned char *)rsdt)) / sizeof(rsdt->sdt_addresses[0]);
108 }
109
110 static unsigned int
get_xsdt_addresses_count(struct acpi_xsdt * xsdt)111 get_xsdt_addresses_count(struct acpi_xsdt *xsdt)
112 {
113 return (xsdt->sdt.length - ((unsigned char*)&xsdt->sdt_addresses - (unsigned char *)xsdt)) / sizeof(xsdt->sdt_addresses[0]);
114 }
115
116 static unsigned int
get_mcfg_allocations_count(struct acpi_mcfg * mcfg)117 get_mcfg_allocations_count(struct acpi_mcfg *mcfg)
118 {
119 return (mcfg->sdt.length - ((unsigned char *)&mcfg->allocations - (unsigned char *)mcfg)) / sizeof(mcfg->allocations[0]);
120 }
121
122 static u8
calculate_checksum(const u8 * bytes,int len)123 calculate_checksum(const u8 *bytes, int len)
124 {
125 u8 checksum = 0;
126
127 while (len-- > 0)
128 checksum -= *(bytes++);
129 return checksum;
130 }
131
132 static struct acpi_sdt *
check_and_map_sdt(struct physmem * physmem,long pagesize,u64 addr,const char * signature,void ** map_addr,u32 * map_length)133 check_and_map_sdt(struct physmem *physmem, long pagesize, u64 addr, const char *signature, void **map_addr, u32 *map_length)
134 {
135 struct acpi_sdt *sdt;
136 char sdt_signature[sizeof(sdt->signature)];
137 u32 length;
138 void *map;
139
140 if (addr + sizeof(*sdt) < addr)
141 return NULL;
142
143 map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(*sdt) + (addr & (pagesize-1)), 0);
144 if (map == (void *)-1)
145 return NULL;
146
147 sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1)));
148 length = sdt->length;
149 memcpy(sdt_signature, sdt->signature, sizeof(sdt->signature));
150
151 physmem_unmap(physmem, map, sizeof(*sdt) + (addr & (pagesize-1)));
152
153 if (memcmp(sdt_signature, signature, sizeof(sdt_signature)) != 0)
154 return NULL;
155 if (length < sizeof(*sdt))
156 return NULL;
157
158 map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), 0);
159 if (map == (void *)-1)
160 return NULL;
161
162 sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1)));
163
164 if (calculate_checksum((u8 *)sdt, sdt->length) != 0)
165 {
166 physmem_unmap(physmem, map, length + (addr & (pagesize-1)));
167 return NULL;
168 }
169
170 *map_addr = map;
171 *map_length = length + (addr & (pagesize-1));
172 return sdt;
173 }
174
175 static int
check_rsdp(struct acpi_rsdp * rsdp)176 check_rsdp(struct acpi_rsdp *rsdp)
177 {
178 if (memcmp(rsdp->signature, "RSD PTR ", sizeof(rsdp->signature)) != 0)
179 return 0;
180 if (calculate_checksum((u8 *)rsdp, sizeof(*rsdp)) != 0)
181 return 0;
182 return 1;
183 }
184
185 static int
check_and_parse_rsdp(struct physmem * physmem,long pagesize,u64 addr,u32 * rsdt_address,u64 * xsdt_address)186 check_and_parse_rsdp(struct physmem *physmem, long pagesize, u64 addr, u32 *rsdt_address, u64 *xsdt_address)
187 {
188 struct acpi_rsdp *rsdp;
189 unsigned char buf[sizeof(*rsdp) + sizeof(*rsdp->rsdp20)];
190 void *map;
191
192 map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(buf) + (addr & (pagesize-1)), 0);
193 if (map == (void *)-1)
194 return 0;
195
196 rsdp = (struct acpi_rsdp *)buf;
197 memcpy(rsdp, (unsigned char *)map + (addr & (pagesize-1)), sizeof(buf));
198
199 physmem_unmap(physmem, map, sizeof(buf));
200
201 if (!check_rsdp(rsdp))
202 return 0;
203
204 *rsdt_address = rsdp->rsdt_address;
205
206 if (rsdp->revision != 0 &&
207 (*rsdp->rsdp20).length == sizeof(*rsdp) + sizeof(*rsdp->rsdp20) &&
208 calculate_checksum((u8 *)rsdp, (*rsdp->rsdp20).length) == 0)
209 *xsdt_address = (*rsdp->rsdp20).xsdt_address;
210 else
211 *xsdt_address = 0;
212
213 return 1;
214 }
215
216 static u64
find_rsdp_address(struct pci_access * a,const char * efisystab,int use_bsd UNUSED,int use_x86bios UNUSED)217 find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSED, int use_x86bios UNUSED)
218 {
219 u64 ullnum;
220 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
221 unsigned long ulnum;
222 #endif
223 char buf[1024];
224 char *endptr;
225 u64 acpi20;
226 u64 acpi;
227 #if defined(__amd64__) || defined(__i386__)
228 struct ecam_access *eacc = a->backend_data;
229 struct physmem *physmem = eacc->physmem;
230 long pagesize = eacc->pagesize;
231 u64 rsdp_addr;
232 u64 addr;
233 void *map;
234 u64 ebda;
235 #endif
236 size_t len;
237 FILE *f;
238
239 if (efisystab[0])
240 {
241 acpi = 0;
242 acpi20 = 0;
243 a->debug("reading EFI system table: %s...", efisystab);
244 f = fopen(efisystab, "r");
245 if (f)
246 {
247 while (fgets(buf, sizeof(buf), f))
248 {
249 len = strlen(buf);
250 while (len > 0 && buf[len-1] == '\n')
251 buf[--len] = '\0';
252 if (strncmp(buf, "ACPI20=", 7) == 0 && isxdigit(buf[7]))
253 {
254 errno = 0;
255 ullnum = strtoull(buf+7, &endptr, 16);
256 if (!errno && !*endptr)
257 acpi20 = ullnum;
258 }
259 else if (strncmp(buf, "ACPI=", 5) == 0 && isxdigit(buf[5]))
260 {
261 errno = 0;
262 ullnum = strtoull(buf+5, &endptr, 16);
263 if (!errno && !*endptr)
264 acpi = ullnum;
265 }
266 }
267 fclose(f);
268 }
269 else
270 a->debug("opening failed: %s...", strerror(errno));
271
272 if (acpi20)
273 return acpi20;
274 else if (acpi)
275 return acpi;
276 }
277
278 #if defined (__FreeBSD__) || defined (__DragonFly__)
279 if (use_bsd)
280 {
281 /* First try FreeBSD kenv hint.acpi.0.rsdp */
282 a->debug("calling kenv hint.acpi.0.rsdp...");
283 if (kenv(KENV_GET, "hint.acpi.0.rsdp", buf, sizeof(buf)) > 0)
284 {
285 errno = 0;
286 ullnum = strtoull(buf, &endptr, 16);
287 if (!errno && !*endptr)
288 return ullnum;
289 }
290
291 /* Then try FreeBSD sysctl machdep.acpi_root */
292 a->debug("calling sysctl machdep.acpi_root...");
293 len = sizeof(ulnum);
294 if (sysctlbyname("machdep.acpi_root", &ulnum, &len, NULL, 0) == 0)
295 return ulnum;
296 }
297 #endif
298
299 #if defined(__NetBSD__)
300 if (use_bsd)
301 {
302 /* Try NetBSD sysctl hw.acpi.root */
303 a->debug("calling sysctl hw.acpi.root...");
304 len = sizeof(ulnum);
305 if (sysctlbyname("hw.acpi.root", &ulnum, &len, NULL, 0) == 0)
306 return ulnum;
307 }
308 #endif
309
310 #if defined(__amd64__) || defined(__i386__)
311 if (use_x86bios)
312 {
313 rsdp_addr = 0;
314
315 /* Scan first kB of Extended BIOS Data Area */
316 a->debug("reading EBDA location from BDA...");
317 map = physmem_map(physmem, 0, 0x40E + 2, 0);
318 if (map != (void *)-1)
319 {
320 ebda = (u64)physmem_readw((unsigned char *)map + 0x40E) << 4;
321 if (physmem_unmap(physmem, map, 0x40E + 2) != 0)
322 a->debug("unmapping of BDA failed: %s...", strerror(errno));
323 if (ebda >= 0x400)
324 {
325 a->debug("scanning first kB of EBDA at 0x%" PCI_U64_FMT_X "...", ebda);
326 map = physmem_map(physmem, ebda & ~(pagesize-1), 1024 + (ebda & (pagesize-1)), 0);
327 if (map != (void *)-1)
328 {
329 for (addr = ebda & (pagesize-1); addr < (ebda & (pagesize-1)) + 1024; addr += 16)
330 {
331 if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr)))
332 {
333 rsdp_addr = (ebda & ~(pagesize-1)) + addr;
334 break;
335 }
336 }
337 if (physmem_unmap(physmem, map, 1024 + (ebda & (pagesize-1))) != 0)
338 a->debug("unmapping of EBDA failed: %s...", strerror(errno));
339 }
340 else
341 a->debug("mapping of EBDA failed: %s...", strerror(errno));
342 }
343 else
344 a->debug("EBDA location 0x%" PCI_U64_FMT_X " is insane...", ebda);
345 }
346 else
347 a->debug("mapping of BDA failed: %s...", strerror(errno));
348
349
350 if (rsdp_addr)
351 return rsdp_addr;
352
353 /* Scan the main BIOS area below 1 MB */
354 a->debug("scanning BIOS below 1 MB...");
355 map = physmem_map(physmem, 0xE0000, 0x20000, 0);
356 if (map != (void *)-1)
357 {
358 for (addr = 0x0; addr < 0x20000; addr += 16)
359 {
360 if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr)))
361 {
362 rsdp_addr = 0xE0000 + addr;
363 break;
364 }
365 }
366 if (physmem_unmap(physmem, map, 0x20000) != 0)
367 a->debug("unmapping of BIOS failed: %s...", strerror(errno));
368 }
369 else
370 a->debug("mapping of BIOS failed: %s...", strerror(errno));
371
372 if (rsdp_addr)
373 return rsdp_addr;
374 }
375 #endif
376
377 return 0;
378 }
379
380 #ifdef PCI_OS_WINDOWS
381 #ifndef ERROR_NOT_FOUND
382 #define ERROR_NOT_FOUND 1168
383 #endif
384 static struct acpi_mcfg *
get_system_firmware_table_acpi_mcfg(struct pci_access * a)385 get_system_firmware_table_acpi_mcfg(struct pci_access *a)
386 {
387 UINT (WINAPI *MyGetSystemFirmwareTable)(DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize);
388 struct acpi_mcfg *mcfg;
389 HMODULE kernel32;
390 DWORD error;
391 DWORD size;
392
393 kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
394 if (!kernel32)
395 return NULL;
396
397 /* Function GetSystemFirmwareTable() is available since Windows Vista. */
398 MyGetSystemFirmwareTable = (void *)GetProcAddress(kernel32, "GetSystemFirmwareTable");
399 if (!MyGetSystemFirmwareTable)
400 return NULL;
401
402 /* 0x41435049 = 'ACPI', 0x4746434D = 'MCFG' */
403 size = MyGetSystemFirmwareTable(0x41435049, 0x4746434D, NULL, 0);
404 if (size == 0)
405 {
406 error = GetLastError();
407 if (error == ERROR_INVALID_FUNCTION) /* ACPI is not present. */
408 return NULL;
409 else if (error == ERROR_NOT_FOUND) /* MCFG table is not present. */
410 return NULL;
411 a->debug("Cannot retrieve ACPI MCFG table: %s.\n", win32_strerror(error));
412 return NULL;
413 }
414
415 mcfg = pci_malloc(a, size);
416
417 if (MyGetSystemFirmwareTable(0x41435049, 0x4746434D, mcfg, size) != size)
418 {
419 error = GetLastError();
420 a->debug("Cannot retrieve ACPI MCFG table: %s.\n", win32_strerror(error));
421 pci_mfree(mcfg);
422 return NULL;
423 }
424
425 if (size < sizeof(*mcfg) || size < mcfg->sdt.length || calculate_checksum((u8 *)mcfg, mcfg->sdt.length) != 0)
426 {
427 a->debug("ACPI MCFG table is broken.\n");
428 pci_mfree(mcfg);
429 return NULL;
430 }
431
432 return mcfg;
433 }
434 #endif
435
436 static struct acpi_mcfg *
find_mcfg(struct pci_access * a,const char * acpimcfg,const char * efisystab,int use_bsd,int use_x86bios)437 find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int use_bsd, int use_x86bios)
438 {
439 struct ecam_access *eacc = a->backend_data;
440 struct physmem *physmem = eacc->physmem;
441 long pagesize = eacc->pagesize;
442 struct acpi_xsdt *xsdt;
443 struct acpi_rsdt *rsdt;
444 struct acpi_mcfg *mcfg;
445 struct acpi_sdt *sdt;
446 unsigned int i, count;
447 u64 rsdp_address;
448 u64 xsdt_address;
449 u32 rsdt_address;
450 void *map_addr;
451 u32 map_length;
452 void *map2_addr;
453 u32 map2_length;
454 long length;
455 FILE *mcfg_file;
456 const char *path;
457 #ifndef PCI_OS_WINDOWS
458 glob_t mcfg_glob;
459 int ret;
460 #endif
461
462 if (acpimcfg[0])
463 {
464 #ifdef PCI_OS_WINDOWS
465 if (strcmp(acpimcfg, "GetSystemFirmwareTable()") == 0)
466 {
467 a->debug("reading ACPI mcfg via GetSystemFirmwareTable()...");
468 mcfg = get_system_firmware_table_acpi_mcfg(a);
469 if (mcfg)
470 return mcfg;
471 a->debug("failed...");
472 }
473 else
474 {
475 path = acpimcfg;
476 #else
477 ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob);
478 if (ret != 0)
479 a->debug("glob(%s) failed: %d...", acpimcfg, ret);
480 else
481 {
482 path = mcfg_glob.gl_pathv[0];
483 #endif
484 a->debug("reading ACPI mcfg file: %s...", path);
485 mcfg_file = fopen(path, "rb");
486 #ifndef PCI_OS_WINDOWS
487 globfree(&mcfg_glob);
488 #endif
489 if (mcfg_file)
490 {
491 if (fseek(mcfg_file, 0, SEEK_END) == 0)
492 length = ftell(mcfg_file);
493 else
494 length = -1;
495 if (length > 0 && (size_t)length > sizeof(*mcfg))
496 {
497 rewind(mcfg_file);
498 mcfg = pci_malloc(a, length);
499 if (fread(mcfg, 1, length, mcfg_file) == (size_t)length &&
500 memcmp(mcfg->sdt.signature, "MCFG", 4) == 0 &&
501 mcfg->sdt.length <= (size_t)length &&
502 calculate_checksum((u8 *)mcfg, mcfg->sdt.length) == 0)
503 {
504 fclose(mcfg_file);
505 return mcfg;
506 }
507 pci_mfree(mcfg);
508 }
509 fclose(mcfg_file);
510 }
511 a->debug("failed...");
512 }
513 }
514
515 a->debug("searching for ACPI RSDP...");
516 rsdp_address = find_rsdp_address(a, efisystab, use_bsd, use_x86bios);
517 if (!rsdp_address)
518 {
519 a->debug("not found...");
520 return NULL;
521 }
522 a->debug("found at 0x%" PCI_U64_FMT_X "...", rsdp_address);
523
524 if (!check_and_parse_rsdp(physmem, pagesize, rsdp_address, &rsdt_address, &xsdt_address))
525 {
526 a->debug("invalid...");
527 return NULL;
528 }
529
530 mcfg = NULL;
531 a->debug("searching for ACPI MCFG (XSDT=0x%" PCI_U64_FMT_X ", RSDT=0x%lx)...", xsdt_address, (unsigned long)rsdt_address);
532
533 xsdt = xsdt_address ? (struct acpi_xsdt *)check_and_map_sdt(physmem, pagesize, xsdt_address, "XSDT", &map_addr, &map_length) : NULL;
534 if (xsdt)
535 {
536 a->debug("via XSDT...");
537 count = get_xsdt_addresses_count(xsdt);
538 for (i = 0; i < count; i++)
539 {
540 sdt = check_and_map_sdt(physmem, pagesize, xsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
541 if (sdt)
542 {
543 mcfg = pci_malloc(a, sdt->length);
544 memcpy(mcfg, sdt, sdt->length);
545 physmem_unmap(physmem, map2_addr, map2_length);
546 break;
547 }
548 }
549 physmem_unmap(physmem, map_addr, map_length);
550 if (mcfg)
551 {
552 a->debug("found...");
553 return mcfg;
554 }
555 }
556
557 rsdt = (struct acpi_rsdt *)check_and_map_sdt(physmem, pagesize, rsdt_address, "RSDT", &map_addr, &map_length);
558 if (rsdt)
559 {
560 a->debug("via RSDT...");
561 count = get_rsdt_addresses_count(rsdt);
562 for (i = 0; i < count; i++)
563 {
564 sdt = check_and_map_sdt(physmem, pagesize, rsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
565 if (sdt)
566 {
567 mcfg = pci_malloc(a, sdt->length);
568 memcpy(mcfg, sdt, sdt->length);
569 physmem_unmap(physmem, map2_addr, map2_length);
570 break;
571 }
572 }
573 physmem_unmap(physmem, map_addr, map_length);
574 if (mcfg)
575 {
576 a->debug("found...");
577 return mcfg;
578 }
579 }
580
581 a->debug("not found...");
582 return NULL;
583 }
584
585 static void
586 get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length)
587 {
588 int buses = (int)mcfg->allocations[i].end_bus_number - (int)mcfg->allocations[i].start_bus_number + 1;
589
590 if (domain)
591 *domain = mcfg->allocations[i].pci_segment;
592 if (start_bus)
593 *start_bus = mcfg->allocations[i].start_bus_number;
594 if (end_bus)
595 *end_bus = mcfg->allocations[i].end_bus_number;
596 if (addr)
597 *addr = mcfg->allocations[i].address;
598 if (length)
599 *length = (buses > 0) ? (buses * 32 * 8 * 4096) : 0;
600 }
601
602 static int
603 parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length)
604 {
605 u64 ullnum;
606 const char *sep1, *sep2;
607 int addr_len;
608 char *endptr;
609 long num;
610 int buses;
611 u64 start_addr;
612
613 if (!*addrs)
614 {
615 if (next)
616 *next = NULL;
617 return 0;
618 }
619
620 endptr = strchr(addrs, ',');
621 if (endptr)
622 addr_len = endptr - addrs;
623 else
624 addr_len = strlen(addrs);
625
626 if (next)
627 *next = endptr ? (endptr+1) : NULL;
628
629 sep1 = memchr(addrs, ':', addr_len);
630 if (!sep1)
631 return 0;
632
633 sep2 = memchr(sep1+1, ':', addr_len - (sep1+1 - addrs));
634 if (!sep2)
635 {
636 sep2 = sep1;
637 sep1 = NULL;
638 }
639
640 if (!sep1)
641 {
642 if (domain)
643 *domain = 0;
644 }
645 else
646 {
647 if (!isxdigit(*addrs))
648 return 0;
649 errno = 0;
650 num = strtol(addrs, &endptr, 16);
651 if (errno || endptr != sep1 || num < 0 || num > INT_MAX)
652 return 0;
653 if (domain)
654 *domain = num;
655 }
656
657 errno = 0;
658 num = strtol(sep1 ? (sep1+1) : addrs, &endptr, 16);
659 if (errno || num < 0 || num > 0xff)
660 return 0;
661 if (start_bus)
662 *start_bus = num;
663
664 buses = -num;
665
666 if (endptr != sep2)
667 {
668 if (*endptr != '-')
669 return 0;
670 errno = 0;
671 num = strtol(endptr+1, &endptr, 16);
672 if (errno || endptr != sep2 || num < 0 || num > 0xff)
673 return 0;
674 buses = num - -buses + 1;
675 if (buses <= 0)
676 return 0;
677 if (end_bus)
678 *end_bus = num;
679 }
680
681 if (!isxdigit(*(sep2+1)))
682 return 0;
683
684 errno = 0;
685 ullnum = strtoull(sep2+1, &endptr, 16);
686 if (errno || (ullnum & 3))
687 return 0;
688 if (addr)
689 *addr = ullnum;
690 start_addr = ullnum;
691
692 if (endptr == addrs + addr_len)
693 {
694 if (buses <= 0)
695 {
696 buses = 0xff - -buses + 1;
697 if (end_bus)
698 *end_bus = 0xff;
699 }
700 if (start_addr + (unsigned)buses * 32 * 8 * 4096 < start_addr)
701 return 0;
702 if (length)
703 *length = buses * 32 * 8 * 4096;
704 }
705 else
706 {
707 if (*endptr != '+' || !isxdigit(*(endptr+1)))
708 return 0;
709 errno = 0;
710 ullnum = strtoull(endptr+1, &endptr, 16);
711 if (errno || endptr != addrs + addr_len || (ullnum & 3) || ullnum > 256 * 32 * 8 * 4096)
712 return 0;
713 if (start_addr + ullnum < start_addr)
714 return 0;
715 if (buses > 0 && ullnum > (unsigned)buses * 32 * 8 * 4096)
716 return 0;
717 if (buses <= 0 && ullnum > (0xff - (unsigned)-buses + 1) * 32 * 8 * 4096)
718 return 0;
719 if (length)
720 *length = ullnum;
721 if (buses <= 0 && end_bus)
722 *end_bus = -buses + (ullnum + 32 * 8 * 4096 - 1) / (32 * 8 * 4096);
723 }
724
725 return 1;
726 }
727
728 static int
729 validate_addrs(const char *addrs)
730 {
731 if (!*addrs)
732 return 1;
733
734 while (addrs)
735 if (!parse_next_addrs(addrs, &addrs, NULL, NULL, NULL, NULL, NULL))
736 return 0;
737
738 return 1;
739 }
740
741 static int
742 calculate_bus_addr(u8 start_bus, u64 start_addr, u32 total_length, u8 bus, u64 *addr, u32 *length)
743 {
744 u32 offset;
745
746 offset = 32*8*4096 * (bus - start_bus);
747 if (offset >= total_length)
748 return 0;
749
750 *addr = start_addr + offset;
751 *length = total_length - offset;
752
753 if (*length > 32*8*4096)
754 *length = 32*8*4096;
755
756 return 1;
757 }
758
759 static int
760 get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, u64 *addr, u32 *length)
761 {
762 int cur_domain;
763 u8 start_bus;
764 u8 end_bus;
765 u64 start_addr;
766 u32 total_length;
767 int i, count;
768
769 if (mcfg)
770 {
771 count = get_mcfg_allocations_count(mcfg);
772 for (i = 0; i < count; i++)
773 {
774 get_mcfg_allocation(mcfg, i, &cur_domain, &start_bus, &end_bus, &start_addr, &total_length);
775 if (domain == cur_domain && bus >= start_bus && bus <= end_bus)
776 return calculate_bus_addr(start_bus, start_addr, total_length, bus, addr, length);
777 }
778 return 0;
779 }
780 else
781 {
782 while (addrs)
783 {
784 if (!parse_next_addrs(addrs, &addrs, &cur_domain, &start_bus, &end_bus, &start_addr, &total_length))
785 return 0;
786 if (domain == cur_domain && bus >= start_bus && bus <= end_bus)
787 return calculate_bus_addr(start_bus, start_addr, total_length, bus, addr, length);
788 }
789 return 0;
790 }
791 }
792
793 static void
794 munmap_reg(struct pci_access *a)
795 {
796 struct ecam_access *eacc = a->backend_data;
797 struct mmap_cache *cache = eacc->cache;
798 struct physmem *physmem = eacc->physmem;
799 long pagesize = eacc->pagesize;
800
801 if (!cache)
802 return;
803
804 physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1)));
805 pci_mfree(cache);
806 eacc->cache = NULL;
807 }
808
809 static int
810 mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int pos, volatile void **reg)
811 {
812 struct ecam_access *eacc = a->backend_data;
813 struct mmap_cache *cache = eacc->cache;
814 struct physmem *physmem = eacc->physmem;
815 long pagesize = eacc->pagesize;
816 const char *addrs;
817 void *map;
818 u64 addr;
819 u32 length;
820 u32 offset;
821
822 if (cache && cache->domain == domain && cache->bus == bus && !!cache->w == !!w)
823 {
824 map = cache->map;
825 addr = cache->addr;
826 length = cache->length;
827 }
828 else
829 {
830 addrs = pci_get_param(a, "ecam.addrs");
831 if (!get_bus_addr(eacc->mcfg, addrs, domain, bus, &addr, &length))
832 return 0;
833
834 map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), w);
835 if (map == (void *)-1)
836 return 0;
837
838 if (cache)
839 physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1)));
840 else
841 cache = eacc->cache = pci_malloc(a, sizeof(*cache));
842
843 cache->map = map;
844 cache->addr = addr;
845 cache->length = length;
846 cache->domain = domain;
847 cache->bus = bus;
848 cache->w = w;
849 }
850
851 /*
852 * Enhanced Configuration Access Mechanism (ECAM) offset according to:
853 * PCI Express Base Specification, Revision 5.0, Version 1.0, Section 7.2.2, Table 7-1, p. 677
854 */
855 offset = ((dev & 0x1f) << 15) | ((func & 0x7) << 12) | (pos & 0xfff);
856
857 if (offset + 4 > length)
858 return 0;
859
860 *reg = (unsigned char *)map + (addr & (pagesize-1)) + offset;
861 return 1;
862 }
863
864 static void
865 ecam_config(struct pci_access *a)
866 {
867 physmem_init_config(a);
868 pci_define_param(a, "ecam.acpimcfg", PCI_PATH_ACPI_MCFG, "Path to the ACPI MCFG table");
869 pci_define_param(a, "ecam.efisystab", PCI_PATH_EFI_SYSTAB, "Path to the EFI system table");
870 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
871 pci_define_param(a, "ecam.bsd", "1", "Use BSD kenv or sysctl to find ACPI MCFG table");
872 #endif
873 #if defined(__amd64__) || defined(__i386__)
874 pci_define_param(a, "ecam.x86bios", "1", "Scan x86 BIOS memory for ACPI MCFG table");
875 #endif
876 pci_define_param(a, "ecam.addrs", "", "Physical addresses of memory mapped PCIe ECAM interface"); /* format: [domain:]start_bus[-end_bus]:start_addr[+length],... */
877 }
878
879 static int
880 ecam_detect(struct pci_access *a)
881 {
882 int use_addrs = 1, use_acpimcfg = 1, use_efisystab = 1, use_bsd = 1, use_x86bios = 1;
883 const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
884 const char *efisystab = pci_get_param(a, "ecam.efisystab");
885 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
886 const char *bsd = pci_get_param(a, "ecam.bsd");
887 #endif
888 #if defined(__amd64__) || defined(__i386__)
889 const char *x86bios = pci_get_param(a, "ecam.x86bios");
890 #endif
891 const char *addrs = pci_get_param(a, "ecam.addrs");
892 struct ecam_access *eacc;
893 #ifndef PCI_OS_WINDOWS
894 glob_t mcfg_glob;
895 int ret;
896 #endif
897
898 if (!*addrs)
899 {
900 a->debug("ecam.addrs was not specified...");
901 use_addrs = 0;
902 }
903
904 if (acpimcfg[0])
905 {
906 #ifndef PCI_OS_WINDOWS
907 ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob);
908 if (ret == 0)
909 {
910 if (access(mcfg_glob.gl_pathv[0], R_OK))
911 {
912 a->debug("cannot access acpimcfg: %s: %s...", mcfg_glob.gl_pathv[0], strerror(errno));
913 use_acpimcfg = 0;
914 }
915 globfree(&mcfg_glob);
916 }
917 else
918 {
919 a->debug("glob(%s) failed: %d...", acpimcfg, ret);
920 use_acpimcfg = 0;
921 }
922 #endif
923 }
924 else
925 use_acpimcfg = 0;
926
927 #ifndef PCI_OS_WINDOWS
928 if (!efisystab[0] || access(efisystab, R_OK))
929 {
930 if (efisystab[0])
931 a->debug("cannot access efisystab: %s: %s...", efisystab, strerror(errno));
932 use_efisystab = 0;
933 }
934 #endif
935
936 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
937 if (strcmp(bsd, "0") == 0)
938 {
939 a->debug("not using BSD kenv/sysctl...");
940 use_bsd = 0;
941 }
942 #else
943 use_bsd = 0;
944 #endif
945
946 #if defined(__amd64__) || defined(__i386__)
947 if (strcmp(x86bios, "0") == 0)
948 {
949 a->debug("not using x86 BIOS...");
950 use_x86bios = 0;
951 }
952 #else
953 use_x86bios = 0;
954 #endif
955
956 if (!use_addrs && !use_acpimcfg && !use_efisystab && !use_bsd && !use_x86bios)
957 {
958 a->debug("no ecam source provided");
959 return 0;
960 }
961
962 if (!validate_addrs(addrs))
963 {
964 a->debug("ecam.addrs has invalid format %s", addrs);
965 return 0;
966 }
967
968 if (physmem_access(a, 0))
969 {
970 a->debug("cannot access physical memory: %s", strerror(errno));
971 return 0;
972 }
973
974 if (!use_addrs)
975 {
976 eacc = pci_malloc(a, sizeof(*eacc));
977
978 eacc->physmem = physmem_open(a, a->writeable);
979 if (!eacc->physmem)
980 {
981 a->debug("cannot open physcal memory: %s.", strerror(errno));
982 pci_mfree(eacc);
983 return 0;
984 }
985
986 eacc->pagesize = physmem_get_pagesize(eacc->physmem);
987 if (eacc->pagesize <= 0)
988 {
989 a->debug("Cannot get page size: %s.", strerror(errno));
990 physmem_close(eacc->physmem);
991 pci_mfree(eacc);
992 return 0;
993 }
994
995 eacc->mcfg = NULL;
996 eacc->cache = NULL;
997 a->backend_data = eacc;
998 eacc->mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
999 if (!eacc->mcfg)
1000 {
1001 physmem_close(eacc->physmem);
1002 pci_mfree(eacc);
1003 a->backend_data = NULL;
1004 return 0;
1005 }
1006 }
1007
1008 if (use_addrs)
1009 a->debug("using with ecam addresses %s", addrs);
1010 else
1011 a->debug("using with%s%s%s%s%s%s", use_acpimcfg ? " acpimcfg=" : "", use_acpimcfg ? acpimcfg : "", use_efisystab ? " efisystab=" : "", use_efisystab ? efisystab : "", use_bsd ? " bsd" : "", use_x86bios ? " x86bios" : "");
1012
1013 return 1;
1014 }
1015
1016 static void
1017 ecam_init(struct pci_access *a)
1018 {
1019 const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
1020 const char *efisystab = pci_get_param(a, "ecam.efisystab");
1021 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
1022 const char *bsd = pci_get_param(a, "ecam.bsd");
1023 #endif
1024 #if defined(__amd64__) || defined(__i386__)
1025 const char *x86bios = pci_get_param(a, "ecam.x86bios");
1026 #endif
1027 const char *addrs = pci_get_param(a, "ecam.addrs");
1028 struct physmem *physmem = NULL;
1029 struct ecam_access *eacc = a->backend_data;
1030 long pagesize = 0;
1031 int use_bsd = 0;
1032 int use_x86bios = 0;
1033 int test_domain = 0;
1034 u8 test_bus = 0;
1035 volatile void *test_reg;
1036
1037 if (!validate_addrs(addrs))
1038 a->error("Option ecam.addrs has invalid address format \"%s\".", addrs);
1039
1040 if (!eacc)
1041 {
1042 physmem = physmem_open(a, a->writeable);
1043 if (!physmem)
1044 a->error("Cannot open physcal memory: %s.", strerror(errno));
1045
1046 pagesize = physmem_get_pagesize(physmem);
1047 if (pagesize <= 0)
1048 a->error("Cannot get page size: %s.", strerror(errno));
1049
1050 eacc = pci_malloc(a, sizeof(*eacc));
1051 eacc->mcfg = NULL;
1052 eacc->cache = NULL;
1053 eacc->physmem = physmem;
1054 eacc->pagesize = pagesize;
1055 a->backend_data = eacc;
1056 }
1057
1058 if (!*addrs)
1059 {
1060 #if defined (__FreeBSD__) || defined (__DragonFly__)
1061 if (strcmp(bsd, "0") != 0)
1062 use_bsd = 1;
1063 #endif
1064 #if defined(__amd64__) || defined(__i386__)
1065 if (strcmp(x86bios, "0") != 0)
1066 use_x86bios = 1;
1067 #endif
1068 if (!eacc->mcfg)
1069 eacc->mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
1070 if (!eacc->mcfg)
1071 a->error("Option ecam.addrs was not specified and ACPI MCFG table cannot be found.");
1072 }
1073
1074 if (eacc->mcfg)
1075 get_mcfg_allocation(eacc->mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL);
1076 else
1077 parse_next_addrs(addrs, NULL, &test_domain, &test_bus, NULL, NULL, NULL);
1078
1079 errno = 0;
1080 if (!mmap_reg(a, 0, test_domain, test_bus, 0, 0, 0, &test_reg))
1081 a->error("Cannot map ecam region: %s.", errno ? strerror(errno) : "Unknown error");
1082 }
1083
1084 static void
1085 ecam_cleanup(struct pci_access *a)
1086 {
1087 struct ecam_access *eacc = a->backend_data;
1088
1089 munmap_reg(a);
1090 physmem_close(eacc->physmem);
1091 pci_mfree(eacc->mcfg);
1092 pci_mfree(eacc);
1093 a->backend_data = NULL;
1094 }
1095
1096 static void
1097 ecam_scan(struct pci_access *a)
1098 {
1099 const char *addrs = pci_get_param(a, "ecam.addrs");
1100 struct ecam_access *eacc = a->backend_data;
1101 u32 *segments;
1102 int i, j, count;
1103 int domain;
1104
1105 segments = pci_malloc(a, 0xFFFF/8);
1106 memset(segments, 0, 0xFFFF/8);
1107
1108 if (eacc->mcfg)
1109 {
1110 count = get_mcfg_allocations_count(eacc->mcfg);
1111 for (i = 0; i < count; i++)
1112 segments[eacc->mcfg->allocations[i].pci_segment / 32] |= 1 << (eacc->mcfg->allocations[i].pci_segment % 32);
1113 }
1114 else
1115 {
1116 while (addrs)
1117 {
1118 if (parse_next_addrs(addrs, &addrs, &domain, NULL, NULL, NULL, NULL))
1119 segments[domain / 32] |= 1 << (domain % 32);
1120 }
1121 }
1122
1123 for (i = 0; i < 0xFFFF/32; i++)
1124 {
1125 if (!segments[i])
1126 continue;
1127 for (j = 0; j < 32; j++)
1128 if (segments[i] & (1 << j))
1129 pci_generic_scan_domain(a, 32*i + j);
1130 }
1131
1132 pci_mfree(segments);
1133 }
1134
1135 static int
1136 ecam_read(struct pci_dev *d, int pos, byte *buf, int len)
1137 {
1138 volatile void *reg;
1139
1140 if (pos >= 4096)
1141 return 0;
1142
1143 if (len != 1 && len != 2 && len != 4)
1144 return pci_generic_block_read(d, pos, buf, len);
1145
1146 if (!mmap_reg(d->access, 0, d->domain, d->bus, d->dev, d->func, pos, ®))
1147 return 0;
1148
1149 switch (len)
1150 {
1151 case 1:
1152 buf[0] = physmem_readb(reg);
1153 break;
1154 case 2:
1155 ((u16 *) buf)[0] = physmem_readw(reg);
1156 break;
1157 case 4:
1158 ((u32 *) buf)[0] = physmem_readl(reg);
1159 break;
1160 }
1161
1162 return 1;
1163 }
1164
1165 static int
1166 ecam_write(struct pci_dev *d, int pos, byte *buf, int len)
1167 {
1168 volatile void *reg;
1169
1170 if (pos >= 4096)
1171 return 0;
1172
1173 if (len != 1 && len != 2 && len != 4)
1174 return pci_generic_block_read(d, pos, buf, len);
1175
1176 if (!mmap_reg(d->access, 1, d->domain, d->bus, d->dev, d->func, pos, ®))
1177 return 0;
1178
1179 switch (len)
1180 {
1181 case 1:
1182 physmem_writeb(buf[0], reg);
1183 break;
1184 case 2:
1185 physmem_writew(((u16 *) buf)[0], reg);
1186 break;
1187 case 4:
1188 physmem_writel(((u32 *) buf)[0], reg);
1189 break;
1190 }
1191
1192 return 1;
1193 }
1194
1195 struct pci_methods pm_ecam = {
1196 .name = "ecam",
1197 .help = "Raw memory mapped access using PCIe ECAM interface",
1198 .config = ecam_config,
1199 .detect = ecam_detect,
1200 .init = ecam_init,
1201 .cleanup = ecam_cleanup,
1202 .scan = ecam_scan,
1203 .fill_info = pci_generic_fill_info,
1204 .read = ecam_read,
1205 .write = ecam_write,
1206 };
1207