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