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