]> mj.ucw.cz Git - pciutils.git/blob - lib/ecam.c
lib: fixup DOE status register bit
[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 get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, off_t *addr, u32 *length)
623 {
624   int cur_domain;
625   u8 start_bus;
626   u8 end_bus;
627   off_t start_addr;
628   u32 total_length;
629   u32 offset;
630   int i, count;
631
632   if (mcfg)
633     {
634       count = get_mcfg_allocations_count(mcfg);
635       for (i = 0; i < count; i++)
636         {
637           get_mcfg_allocation(mcfg, i, &cur_domain, &start_bus, &end_bus, &start_addr, &total_length);
638           if (domain == cur_domain && bus >= start_bus && bus <= end_bus)
639             {
640               offset = 32*8*4096 * (bus - start_bus);
641               if (offset >= total_length)
642                 return 0;
643               *addr = start_addr + offset;
644               *length = total_length - offset;
645               return 1;
646             }
647         }
648       return 0;
649     }
650   else
651     {
652       while (addrs)
653         {
654           if (!parse_next_addrs(addrs, &addrs, &cur_domain, &start_bus, &end_bus, &start_addr, &total_length))
655             return 0;
656           if (domain == cur_domain && bus >= start_bus && bus <= end_bus)
657             {
658               offset = 32*8*4096 * (bus - start_bus);
659               if (offset >= total_length)
660                 return 0;
661               *addr = start_addr + offset;
662               *length = total_length - offset;
663               return 1;
664             }
665         }
666       return 0;
667     }
668 }
669
670 struct mmap_cache
671 {
672   void *map;
673   off_t addr;
674   u32 length;
675   int domain;
676   u8 bus;
677   int w;
678 };
679
680 struct ecam_aux
681 {
682   struct acpi_mcfg *mcfg;
683   struct mmap_cache *cache;
684 };
685
686 static void
687 munmap_reg(struct pci_access *a)
688 {
689   struct ecam_aux *aux = a->aux;
690   struct mmap_cache *cache = aux->cache;
691
692   if (!cache)
693     return;
694
695   munmap(cache->map, cache->length + (cache->addr & (pagesize-1)));
696   pci_mfree(cache);
697   aux->cache = NULL;
698 }
699
700 static int
701 mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int pos, volatile void **reg)
702 {
703   struct ecam_aux *aux = a->aux;
704   struct mmap_cache *cache = aux->cache;
705   const char *addrs;
706   void *map;
707   off_t addr;
708   u32 length;
709   u32 offset;
710
711   if (cache && cache->domain == domain && cache->bus == bus && !!cache->w == !!w)
712     {
713       map = cache->map;
714       addr = cache->addr;
715       length = cache->length;
716     }
717   else
718     {
719       addrs = pci_get_param(a, "ecam.addrs");
720       if (!get_bus_addr(aux->mcfg, addrs, domain, bus, &addr, &length))
721         return 0;
722
723       map = mmap(NULL, length + (addr & (pagesize-1)), w ? PROT_WRITE : PROT_READ, MAP_SHARED, a->fd, addr & ~(pagesize-1));
724       if (map == MAP_FAILED)
725         return 0;
726
727       if (cache)
728         munmap(cache->map, cache->length + (cache->addr & (pagesize-1)));
729       else
730         cache = aux->cache = pci_malloc(a, sizeof(*cache));
731
732       cache->map = map;
733       cache->addr = addr;
734       cache->length = length;
735       cache->domain = domain;
736       cache->bus = bus;
737       cache->w = w;
738     }
739
740   /*
741    * Enhanced Configuration Access Mechanism (ECAM) offset according to:
742    * PCI Express Base Specification, Revision 5.0, Version 1.0, Section 7.2.2, Table 7-1, p. 677
743    */
744   offset = ((dev & 0x1f) << 15) | ((func & 0x7) << 12) | (pos & 0xfff);
745
746   if (offset + 4 > length)
747     return 0;
748
749   *reg = (unsigned char *)map + (addr & (pagesize-1)) + offset;
750   return 1;
751 }
752
753 static void
754 writeb(unsigned char value, volatile void *addr)
755 {
756   *(volatile unsigned char *)addr = value;
757 }
758
759 static void
760 writew(unsigned short value, volatile void *addr)
761 {
762   *(volatile unsigned short *)addr = value;
763 }
764
765 static void
766 writel(unsigned int value, volatile void *addr)
767 {
768   *(volatile unsigned int *)addr = value;
769 }
770
771 static unsigned char
772 readb(volatile void *addr)
773 {
774   return *(volatile unsigned char *)addr;
775 }
776
777 static unsigned short
778 readw(volatile void *addr)
779 {
780   return *(volatile unsigned short *)addr;
781 }
782
783 static unsigned int
784 readl(volatile void *addr)
785 {
786   return *(volatile unsigned int *)addr;
787 }
788
789 static void
790 ecam_config(struct pci_access *a)
791 {
792   pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
793   pci_define_param(a, "ecam.acpimcfg", PCI_PATH_ACPI_MCFG, "Path to the ACPI MCFG table");
794   pci_define_param(a, "ecam.efisystab", PCI_PATH_EFI_SYSTAB, "Path to the EFI system table");
795 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
796   pci_define_param(a, "ecam.bsd", "1", "Use BSD kenv or sysctl to find ACPI MCFG table");
797 #endif
798 #if defined(__amd64__) || defined(__i386__)
799   pci_define_param(a, "ecam.x86bios", "1", "Scan x86 BIOS memory for ACPI MCFG table");
800 #endif
801   pci_define_param(a, "ecam.addrs", "", "Physical addresses of memory mapped PCIe ECAM interface"); /* format: [domain:]start_bus[-end_bus]:start_addr[+length],... */
802 }
803
804 static int
805 ecam_detect(struct pci_access *a)
806 {
807   int use_addrs = 1, use_acpimcfg = 1, use_efisystab = 1, use_bsd = 1, use_x86bios = 1;
808   const char *devmem = pci_get_param(a, "devmem.path");
809   const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
810   const char *efisystab = pci_get_param(a, "ecam.efisystab");
811 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
812   const char *bsd = pci_get_param(a, "ecam.bsd");
813 #endif
814 #if defined(__amd64__) || defined(__i386__)
815   const char *x86bios = pci_get_param(a, "ecam.x86bios");
816 #endif
817   const char *addrs = pci_get_param(a, "ecam.addrs");
818   glob_t mcfg_glob;
819   int ret;
820
821   if (!*addrs)
822     {
823       a->debug("ecam.addrs was not specified...");
824       use_addrs = 0;
825     }
826
827   if (acpimcfg[0])
828     {
829       ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob);
830       if (ret == 0)
831         {
832           if (access(mcfg_glob.gl_pathv[0], R_OK))
833             {
834               a->debug("cannot access acpimcfg: %s: %s...", mcfg_glob.gl_pathv[0], strerror(errno));
835               use_acpimcfg = 0;
836             }
837           globfree(&mcfg_glob);
838         }
839       else
840         {
841           a->debug("glob(%s) failed: %d...", acpimcfg, ret);
842           use_acpimcfg = 0;
843         }
844     }
845   else
846     use_acpimcfg = 0;
847
848   if (access(efisystab, R_OK))
849     {
850       if (efisystab[0])
851         a->debug("cannot access efisystab: %s: %s...", efisystab, strerror(errno));
852       use_efisystab = 0;
853     }
854
855 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
856   if (strcmp(bsd, "0") == 0)
857     {
858       a->debug("not using BSD kenv/sysctl...");
859       use_bsd = 0;
860     }
861 #else
862   use_bsd = 0;
863 #endif
864
865 #if defined(__amd64__) || defined(__i386__)
866   if (strcmp(x86bios, "0") == 0)
867     {
868       a->debug("not using x86 BIOS...");
869       use_x86bios = 0;
870     }
871 #else
872   use_x86bios = 0;
873 #endif
874
875   if (!use_addrs && !use_acpimcfg && !use_efisystab && !use_bsd && !use_x86bios)
876     {
877       a->debug("no ecam source provided");
878       return 0;
879     }
880
881   if (!validate_addrs(addrs))
882     {
883       a->debug("ecam.addrs has invalid format %s", addrs);
884       return 0;
885     }
886
887   if (access(devmem, R_OK))
888     {
889       a->debug("cannot access physical memory via %s: %s", devmem, strerror(errno));
890       return 0;
891     }
892
893   if (use_addrs)
894     a->debug("using %s with ecam addresses %s", devmem, addrs);
895   else
896     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" : "");
897
898   return 1;
899 }
900
901 static void
902 ecam_init(struct pci_access *a)
903 {
904   const char *devmem = pci_get_param(a, "devmem.path");
905   const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
906   const char *efisystab = pci_get_param(a, "ecam.efisystab");
907 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
908   const char *bsd = pci_get_param(a, "ecam.bsd");
909 #endif
910 #if defined(__amd64__) || defined(__i386__)
911   const char *x86bios = pci_get_param(a, "ecam.x86bios");
912 #endif
913   const char *addrs = pci_get_param(a, "ecam.addrs");
914   struct acpi_mcfg *mcfg = NULL;
915   struct ecam_aux *aux = NULL;
916   int use_bsd = 0;
917   int use_x86bios = 0;
918   int test_domain = 0;
919   u8 test_bus = 0;
920   volatile void *test_reg;
921
922   pagesize = sysconf(_SC_PAGESIZE);
923   if (pagesize < 0)
924     a->error("Cannot get page size: %s.", strerror(errno));
925
926   if (!validate_addrs(addrs))
927     a->error("Option ecam.addrs has invalid address format \"%s\".", addrs);
928
929   a->fd = open(devmem, (a->writeable ? O_RDWR : O_RDONLY) | O_DSYNC);
930   if (a->fd < 0)
931     a->error("Cannot open %s: %s.", devmem, strerror(errno));
932
933   if (!*addrs)
934     {
935 #if defined (__FreeBSD__) || defined (__DragonFly__)
936       if (strcmp(bsd, "0") != 0)
937         use_bsd = 1;
938 #endif
939 #if defined(__amd64__) || defined(__i386__)
940       if (strcmp(x86bios, "0") != 0)
941         use_x86bios = 1;
942 #endif
943       mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
944       if (!mcfg)
945         a->error("Option ecam.addrs was not specified and ACPI MCFG table cannot be found.");
946     }
947
948   aux = pci_malloc(a, sizeof(*aux));
949   aux->mcfg = mcfg;
950   aux->cache = NULL;
951   a->aux = aux;
952
953   if (mcfg)
954     get_mcfg_allocation(mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL);
955   else
956     parse_next_addrs(addrs, NULL, &test_domain, &test_bus, NULL, NULL, NULL);
957
958   errno = 0;
959   if (!mmap_reg(a, 0, test_domain, test_bus, 0, 0, 0, &test_reg))
960     a->error("Cannot map ecam region: %s.", errno ? strerror(errno) : "Unknown error");
961 }
962
963 static void
964 ecam_cleanup(struct pci_access *a)
965 {
966   struct ecam_aux *aux = a->aux;
967
968   if (a->fd < 0)
969     return;
970
971   munmap_reg(a);
972   pci_mfree(aux->mcfg);
973   pci_mfree(aux);
974
975   close(a->fd);
976   a->fd = -1;
977 }
978
979 static void
980 ecam_scan(struct pci_access *a)
981 {
982   const char *addrs = pci_get_param(a, "ecam.addrs");
983   struct ecam_aux *aux = a->aux;
984   u32 *segments;
985   int i, j, count;
986   int domain;
987
988   segments = pci_malloc(a, 0xFFFF/8);
989   memset(segments, 0, 0xFFFF/8);
990
991   if (aux->mcfg)
992     {
993       count = get_mcfg_allocations_count(aux->mcfg);
994       for (i = 0; i < count; i++)
995         segments[aux->mcfg->allocations[i].pci_segment / 32] |= 1 << (aux->mcfg->allocations[i].pci_segment % 32);
996     }
997   else
998     {
999       while (addrs)
1000         {
1001           if (parse_next_addrs(addrs, &addrs, &domain, NULL, NULL, NULL, NULL))
1002             segments[domain / 32] |= 1 << (domain % 32);
1003         }
1004     }
1005
1006   for (i = 0; i < 0xFFFF/32; i++)
1007     {
1008       if (!segments[i])
1009         continue;
1010       for (j = 0; j < 32; j++)
1011         if (segments[i] & (1 << j))
1012           pci_generic_scan_domain(a, 32*i + j);
1013     }
1014
1015   pci_mfree(segments);
1016 }
1017
1018 static int
1019 ecam_read(struct pci_dev *d, int pos, byte *buf, int len)
1020 {
1021   volatile void *reg;
1022
1023   if (pos >= 4096)
1024     return 0;
1025
1026   if (len != 1 && len != 2 && len != 4)
1027     return pci_generic_block_read(d, pos, buf, len);
1028
1029   if (!mmap_reg(d->access, 0, d->domain, d->bus, d->dev, d->func, pos, &reg))
1030     return 0;
1031
1032   switch (len)
1033     {
1034     case 1:
1035       buf[0] = readb(reg);
1036       break;
1037     case 2:
1038       ((u16 *) buf)[0] = readw(reg);
1039       break;
1040     case 4:
1041       ((u32 *) buf)[0] = readl(reg);
1042       break;
1043     }
1044
1045   return 1;
1046 }
1047
1048 static int
1049 ecam_write(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, 1, d->domain, d->bus, d->dev, d->func, pos, &reg))
1060     return 0;
1061
1062   switch (len)
1063     {
1064     case 1:
1065       writeb(buf[0], reg);
1066       break;
1067     case 2:
1068       writew(((u16 *) buf)[0], reg);
1069       break;
1070     case 4:
1071       writel(((u32 *) buf)[0], reg);
1072       break;
1073     }
1074
1075   return 1;
1076 }
1077
1078 struct pci_methods pm_ecam = {
1079   "ecam",
1080   "Raw memory mapped access using PCIe ECAM interface",
1081   ecam_config,
1082   ecam_detect,
1083   ecam_init,
1084   ecam_cleanup,
1085   ecam_scan,
1086   pci_generic_fill_info,
1087   ecam_read,
1088   ecam_write,
1089   NULL,                                 /* read_vpd */
1090   NULL,                                 /* init_dev */
1091   NULL                                  /* cleanup_dev */
1092 };