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