From 7d347ab73a39d37bb3134b8a1c7970030a19e009 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 8 May 2023 21:15:07 +0200 Subject: libpci: Move physical memory mapping mmap() code from ecam/mmio-ports to physmem-posix.c file This deduplicates physical memory mapping mmap() code found in ecam and mmio-ports backends into common functions with new physmem API. This new physmem API allows to implement also non-mmap() variants of physical memory mapping. --- lib/Makefile | 6 + lib/ecam.c | 318 +++++++++++++++++++++++---------------------------- lib/mmio-ports.c | 192 +++++++++++++------------------ lib/physmem-access.h | 52 +++++++++ lib/physmem-posix.c | 95 +++++++++++++++ lib/physmem.h | 19 +++ 6 files changed, 393 insertions(+), 289 deletions(-) create mode 100644 lib/physmem-access.h create mode 100644 lib/physmem-posix.c create mode 100644 lib/physmem.h diff --git a/lib/Makefile b/lib/Makefile index 4110ad3..5c438eb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -79,6 +79,12 @@ ifdef PCI_OS_WINDOWS OBJS += win32-helpers endif +ifndef PCI_OS_WINDOWS +ifndef PCI_OS_DJGPP +OBJS += physmem-posix +endif +endif + all: $(PCILIB) $(PCILIBPC) ifeq ($(SHARED),no) diff --git a/lib/ecam.c b/lib/ecam.c index c72eae6..cb479c6 100644 --- a/lib/ecam.c +++ b/lib/ecam.c @@ -8,14 +8,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type - * as 32-bit variant of off_t type is signed and so it cannot represent all - * possible 32-bit offsets. It is required because off_t type is used by mmap(). - */ -#define _FILE_OFFSET_BITS 64 - #include "internal.h" +#include "physmem.h" +#include "physmem-access.h" #include #include @@ -24,9 +19,6 @@ #include #include -#include -#include -#include #include #include @@ -38,12 +30,6 @@ #include #endif -#ifndef OFF_MAX -#define OFF_MAX (off_t)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 1) -#endif - -static long pagesize; - struct acpi_rsdp { char signature[8]; u8 checksum; @@ -92,6 +78,23 @@ struct acpi_mcfg { } allocations[0]; } PCI_PACKED; +struct mmap_cache { + void *map; + u64 addr; + u32 length; + int domain; + u8 bus; + int w; +}; + +// Back-end data linked to struct pci_access +struct ecam_access { + struct acpi_mcfg *mcfg; + struct mmap_cache *cache; + struct physmem *physmem; + long pagesize; +}; + static unsigned int get_rsdt_addresses_count(struct acpi_rsdt *rsdt) { @@ -121,40 +124,40 @@ calculate_checksum(const u8 *bytes, int len) } static struct acpi_sdt * -check_and_map_sdt(int fd, u64 addr, const char *signature, void **map_addr, u32 *map_length) +check_and_map_sdt(struct physmem *physmem, long pagesize, u64 addr, const char *signature, void **map_addr, u32 *map_length) { struct acpi_sdt *sdt; char sdt_signature[sizeof(sdt->signature)]; u32 length; void *map; - if (addr > OFF_MAX - sizeof(*sdt)) + if (addr + sizeof(*sdt) < addr) return NULL; - map = mmap(NULL, sizeof(*sdt) + (addr & (pagesize-1)), PROT_READ, MAP_SHARED, fd, addr & ~(pagesize-1)); - if (map == MAP_FAILED) + map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(*sdt) + (addr & (pagesize-1)), 0); + if (map == (void *)-1) return NULL; sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1))); length = sdt->length; memcpy(sdt_signature, sdt->signature, sizeof(sdt->signature)); - munmap(map, sizeof(*sdt) + (addr & (pagesize-1))); + physmem_unmap(physmem, map, sizeof(*sdt) + (addr & (pagesize-1))); if (memcmp(sdt_signature, signature, sizeof(sdt_signature)) != 0) return NULL; if (length < sizeof(*sdt)) return NULL; - map = mmap(NULL, length + (addr & (pagesize-1)), PROT_READ, MAP_SHARED, fd, addr & ~(pagesize-1)); - if (map == MAP_FAILED) + map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), 0); + if (map == (void *)-1) return NULL; sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1))); if (calculate_checksum((u8 *)sdt, sdt->length) != 0) { - munmap(map, length + (addr & (pagesize-1))); + physmem_unmap(physmem, map, length + (addr & (pagesize-1))); return NULL; } @@ -174,20 +177,20 @@ check_rsdp(struct acpi_rsdp *rsdp) } static int -check_and_parse_rsdp(int fd, off_t addr, u32 *rsdt_address, u64 *xsdt_address) +check_and_parse_rsdp(struct physmem *physmem, long pagesize, u64 addr, u32 *rsdt_address, u64 *xsdt_address) { struct acpi_rsdp *rsdp; unsigned char buf[sizeof(*rsdp) + sizeof(*rsdp->rsdp20)]; void *map; - map = mmap(NULL, sizeof(buf) + (addr & (pagesize-1)), PROT_READ, MAP_SHARED, fd, addr & ~(pagesize-1)); - if (map == MAP_FAILED) + map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(buf) + (addr & (pagesize-1)), 0); + if (map == (void *)-1) return 0; rsdp = (struct acpi_rsdp *)buf; memcpy(rsdp, (unsigned char *)map + (addr & (pagesize-1)), sizeof(buf)); - munmap(map, sizeof(buf)); + physmem_unmap(physmem, map, sizeof(buf)); if (!check_rsdp(rsdp)) return 0; @@ -204,20 +207,22 @@ check_and_parse_rsdp(int fd, off_t addr, u32 *rsdt_address, u64 *xsdt_address) return 1; } -static off_t +static u64 find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSED, int use_x86bios UNUSED) { - unsigned long long ullnum; + u64 ullnum; #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__) unsigned long ulnum; #endif char buf[1024]; char *endptr; - off_t acpi20; - off_t acpi; + u64 acpi20; + u64 acpi; #if defined(__amd64__) || defined(__i386__) - off_t rsdp_addr; - off_t addr; + struct ecam_access *eacc = a->backend_data; + struct physmem *physmem = eacc->physmem; + u64 rsdp_addr; + u64 addr; void *map; #endif size_t len; @@ -240,19 +245,21 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE { errno = 0; ullnum = strtoull(buf+7, &endptr, 16); - if (!errno && !*endptr && ullnum <= OFF_MAX) + if (!errno && !*endptr) acpi20 = ullnum; } else if (strncmp(buf, "ACPI=", 5) == 0 && isxdigit(buf[5])) { errno = 0; ullnum = strtoull(buf+5, &endptr, 16); - if (!errno && !*endptr && ullnum <= OFF_MAX) + if (!errno && !*endptr) acpi = ullnum; } } fclose(f); } + else + a->debug("opening failed: %s...", strerror(errno)); if (acpi20) return acpi20; @@ -269,14 +276,14 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE { errno = 0; ullnum = strtoull(buf, &endptr, 16); - if (!errno && !*endptr && ullnum <= OFF_MAX) + if (!errno && !*endptr) return ullnum; } /* Then try FreeBSD sysctl machdep.acpi_root */ a->debug("calling sysctl machdep.acpi_root..."); len = sizeof(ulnum); - if (sysctlbyname("machdep.acpi_root", &ulnum, &len, NULL, 0) == 0 && ulnum <= OFF_MAX) + if (sysctlbyname("machdep.acpi_root", &ulnum, &len, NULL, 0) == 0) return ulnum; } #endif @@ -287,7 +294,7 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE /* Try NetBSD sysctl hw.acpi.root */ a->debug("calling sysctl hw.acpi.root..."); len = sizeof(ulnum); - if (sysctlbyname("hw.acpi.root", &ulnum, &len, NULL, 0) == 0 && ulnum <= OFF_MAX) + if (sysctlbyname("hw.acpi.root", &ulnum, &len, NULL, 0) == 0) return ulnum; } #endif @@ -299,8 +306,8 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE /* Scan first kB of Extended BIOS Data Area */ a->debug("scanning first kB of EBDA..."); - map = mmap(NULL, 0x40E + 1024, PROT_READ, MAP_SHARED, a->fd, 0); - if (map != MAP_FAILED) + map = physmem_map(physmem, 0, 0x40E + 1024, 0); + if (map != (void *)-1) { for (addr = 0x40E; addr < 0x40E + 1024; addr += 16) { @@ -310,16 +317,19 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE break; } } - munmap(map, 0x40E + 1024); + if (physmem_unmap(physmem, map, 0x40E + 1024) != 0) + a->debug("unmapping of EBDA failed: %s...", strerror(errno)); } + else + a->debug("mapping of EBDA failed: %s...", strerror(errno)); if (rsdp_addr) return rsdp_addr; /* Scan the main BIOS area below 1 MB */ a->debug("scanning BIOS below 1 MB..."); - map = mmap(NULL, 0x20000, PROT_READ, MAP_SHARED, a->fd, 0xE0000); - if (map != MAP_FAILED) + map = physmem_map(physmem, 0xE0000, 0x20000, 0); + if (map != (void *)-1) { for (addr = 0x0; addr < 0x20000; addr += 16) { @@ -329,8 +339,11 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE break; } } - munmap(map, 0x20000); + if (physmem_unmap(physmem, map, 0x20000) != 0) + a->debug("unmapping of BIOS failed: %s...", strerror(errno)); } + else + a->debug("mapping of BIOS failed: %s...", strerror(errno)); if (rsdp_addr) return rsdp_addr; @@ -343,20 +356,24 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE static struct acpi_mcfg * find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int use_bsd, int use_x86bios) { + struct ecam_access *eacc = a->backend_data; + struct physmem *physmem = eacc->physmem; + long pagesize = eacc->pagesize; struct acpi_xsdt *xsdt; struct acpi_rsdt *rsdt; struct acpi_mcfg *mcfg; struct acpi_sdt *sdt; unsigned int i, count; - off_t rsdp_address; + u64 rsdp_address; u64 xsdt_address; u32 rsdt_address; void *map_addr; u32 map_length; void *map2_addr; u32 map2_length; - off_t length; - int mcfg_fd; + long length; + FILE *mcfg_file; + const char *path; glob_t mcfg_glob; int ret; @@ -365,26 +382,30 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob); if (ret == 0) { - a->debug("reading acpi mcfg file: %s...", mcfg_glob.gl_pathv[0]); - mcfg_fd = open(mcfg_glob.gl_pathv[0], O_RDONLY); + path = mcfg_glob.gl_pathv[0]; + a->debug("reading acpi mcfg file: %s...", path); + mcfg_file = fopen(path, "rb"); globfree(&mcfg_glob); - if (mcfg_fd >= 0) + if (mcfg_file) { - length = lseek(mcfg_fd, 0, SEEK_END); - if (length != (off_t)-1 && length > (off_t)sizeof(*mcfg)) + if (fseek(mcfg_file, 0, SEEK_END) == 0) + length = ftell(mcfg_file); + else + length = -1; + if (length > 0 && (size_t)length > sizeof(*mcfg)) { - lseek(mcfg_fd, 0, SEEK_SET); + rewind(mcfg_file); mcfg = pci_malloc(a, length); - if (read(mcfg_fd, mcfg, length) == length && + if (fread(mcfg, 1, length, mcfg_file) == (size_t)length && memcmp(mcfg->sdt.signature, "MCFG", 4) == 0 && - mcfg->sdt.length <= length && + mcfg->sdt.length <= (size_t)length && calculate_checksum((u8 *)mcfg, mcfg->sdt.length) == 0) { - close(mcfg_fd); + fclose(mcfg_file); return mcfg; } } - close(mcfg_fd); + fclose(mcfg_file); } a->debug("failed..."); } @@ -399,34 +420,34 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int a->debug("not found..."); return NULL; } - a->debug("found at 0x%llx...", (unsigned long long)rsdp_address); + a->debug("found at 0x%" PCI_U64_FMT_X "...", rsdp_address); - if (!check_and_parse_rsdp(a->fd, rsdp_address, &rsdt_address, &xsdt_address)) + if (!check_and_parse_rsdp(physmem, pagesize, rsdp_address, &rsdt_address, &xsdt_address)) { a->debug("invalid..."); return NULL; } mcfg = NULL; - a->debug("searching for ACPI MCFG (XSDT=0x%llx, RSDT=0x%x)...", (unsigned long long)xsdt_address, rsdt_address); + a->debug("searching for ACPI MCFG (XSDT=0x%" PCI_U64_FMT_X ", RSDT=0x%lx)...", xsdt_address, (unsigned long)rsdt_address); - xsdt = xsdt_address ? (struct acpi_xsdt *)check_and_map_sdt(a->fd, xsdt_address, "XSDT", &map_addr, &map_length) : NULL; + xsdt = xsdt_address ? (struct acpi_xsdt *)check_and_map_sdt(physmem, pagesize, xsdt_address, "XSDT", &map_addr, &map_length) : NULL; if (xsdt) { a->debug("via XSDT..."); count = get_xsdt_addresses_count(xsdt); for (i = 0; i < count; i++) { - sdt = check_and_map_sdt(a->fd, xsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length); + sdt = check_and_map_sdt(physmem, pagesize, xsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length); if (sdt) { mcfg = pci_malloc(a, sdt->length); memcpy(mcfg, sdt, sdt->length); - munmap(map2_addr, map2_length); + physmem_unmap(physmem, map2_addr, map2_length); break; } } - munmap(map_addr, map_length); + physmem_unmap(physmem, map_addr, map_length); if (mcfg) { a->debug("found..."); @@ -434,23 +455,23 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int } } - rsdt = (struct acpi_rsdt *)check_and_map_sdt(a->fd, rsdt_address, "RSDT", &map_addr, &map_length); + rsdt = (struct acpi_rsdt *)check_and_map_sdt(physmem, pagesize, rsdt_address, "RSDT", &map_addr, &map_length); if (rsdt) { a->debug("via RSDT..."); count = get_rsdt_addresses_count(rsdt); for (i = 0; i < count; i++) { - sdt = check_and_map_sdt(a->fd, rsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length); + sdt = check_and_map_sdt(physmem, pagesize, rsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length); if (sdt) { mcfg = pci_malloc(a, sdt->length); memcpy(mcfg, sdt, sdt->length); - munmap(map2_addr, map2_length); + physmem_unmap(physmem, map2_addr, map2_length); break; } } - munmap(map_addr, map_length); + physmem_unmap(physmem, map_addr, map_length); if (mcfg) { a->debug("found..."); @@ -463,7 +484,7 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int } static void -get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *start_bus, u8 *end_bus, off_t *addr, u32 *length) +get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length) { int buses = (int)mcfg->allocations[i].end_bus_number - (int)mcfg->allocations[i].start_bus_number + 1; @@ -480,15 +501,15 @@ get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *sta } static int -parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bus, u8 *end_bus, off_t *addr, u32 *length) +parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length) { - unsigned long long ullnum; + u64 ullnum; const char *sep1, *sep2; int addr_len; char *endptr; long num; int buses; - unsigned long long start_addr; + u64 start_addr; if (!*addrs) { @@ -563,7 +584,7 @@ parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bu errno = 0; ullnum = strtoull(sep2+1, &endptr, 16); - if (errno || (ullnum & 3) || ullnum > OFF_MAX) + if (errno || (ullnum & 3)) return 0; if (addr) *addr = ullnum; @@ -577,7 +598,7 @@ parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bu if (end_bus) *end_bus = 0xff; } - if ((unsigned)buses * 32 * 8 * 4096 > OFF_MAX - start_addr) + if (start_addr + (unsigned)buses * 32 * 8 * 4096 < start_addr) return 0; if (length) *length = buses * 32 * 8 * 4096; @@ -588,9 +609,9 @@ parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bu return 0; errno = 0; ullnum = strtoull(endptr+1, &endptr, 16); - if (errno || endptr != addrs + addr_len || (ullnum & 3) || ullnum > OFF_MAX || ullnum > 256 * 32 * 8 * 4096) + if (errno || endptr != addrs + addr_len || (ullnum & 3) || ullnum > 256 * 32 * 8 * 4096) return 0; - if (ullnum > OFF_MAX - start_addr) + if (start_addr + ullnum < start_addr) return 0; if (buses > 0 && ullnum > (unsigned)buses * 32 * 8 * 4096) return 0; @@ -619,7 +640,7 @@ validate_addrs(const char *addrs) } static int -calculate_bus_addr(u8 start_bus, off_t start_addr, u32 total_length, u8 bus, off_t *addr, u32 *length) +calculate_bus_addr(u8 start_bus, u64 start_addr, u32 total_length, u8 bus, u64 *addr, u32 *length) { u32 offset; @@ -637,12 +658,12 @@ calculate_bus_addr(u8 start_bus, off_t start_addr, u32 total_length, u8 bus, off } static int -get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, off_t *addr, u32 *length) +get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, u64 *addr, u32 *length) { int cur_domain; u8 start_bus; u8 end_bus; - off_t start_addr; + u64 start_addr; u32 total_length; int i, count; @@ -670,33 +691,18 @@ get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, off_ } } -struct mmap_cache -{ - void *map; - off_t addr; - u32 length; - int domain; - u8 bus; - int w; -}; - -// Back-end data linked to struct pci_access -struct ecam_access -{ - struct acpi_mcfg *mcfg; - struct mmap_cache *cache; -}; - static void munmap_reg(struct pci_access *a) { struct ecam_access *eacc = a->backend_data; struct mmap_cache *cache = eacc->cache; + struct physmem *physmem = eacc->physmem; + long pagesize = eacc->pagesize; if (!cache) return; - munmap(cache->map, cache->length + (cache->addr & (pagesize-1))); + physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1))); pci_mfree(cache); eacc->cache = NULL; } @@ -706,9 +712,11 @@ mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int p { struct ecam_access *eacc = a->backend_data; struct mmap_cache *cache = eacc->cache; + struct physmem *physmem = eacc->physmem; + long pagesize = eacc->pagesize; const char *addrs; void *map; - off_t addr; + u64 addr; u32 length; u32 offset; @@ -724,12 +732,12 @@ mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int p if (!get_bus_addr(eacc->mcfg, addrs, domain, bus, &addr, &length)) return 0; - map = mmap(NULL, length + (addr & (pagesize-1)), w ? PROT_WRITE : PROT_READ, MAP_SHARED, a->fd, addr & ~(pagesize-1)); - if (map == MAP_FAILED) + map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), w); + if (map == (void *)-1) return 0; if (cache) - munmap(cache->map, cache->length + (cache->addr & (pagesize-1))); + physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1))); else cache = eacc->cache = pci_malloc(a, sizeof(*cache)); @@ -754,46 +762,10 @@ mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int p return 1; } -static void -writeb(unsigned char value, volatile void *addr) -{ - *(volatile unsigned char *)addr = value; -} - -static void -writew(unsigned short value, volatile void *addr) -{ - *(volatile unsigned short *)addr = value; -} - -static void -writel(unsigned int value, volatile void *addr) -{ - *(volatile unsigned int *)addr = value; -} - -static unsigned char -readb(volatile void *addr) -{ - return *(volatile unsigned char *)addr; -} - -static unsigned short -readw(volatile void *addr) -{ - return *(volatile unsigned short *)addr; -} - -static unsigned int -readl(volatile void *addr) -{ - return *(volatile unsigned int *)addr; -} - static void ecam_config(struct pci_access *a) { - pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device"); + physmem_init_config(a); pci_define_param(a, "ecam.acpimcfg", PCI_PATH_ACPI_MCFG, "Path to the ACPI MCFG table"); pci_define_param(a, "ecam.efisystab", PCI_PATH_EFI_SYSTAB, "Path to the EFI system table"); #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__) @@ -809,7 +781,6 @@ static int ecam_detect(struct pci_access *a) { int use_addrs = 1, use_acpimcfg = 1, use_efisystab = 1, use_bsd = 1, use_x86bios = 1; - const char *devmem = pci_get_param(a, "devmem.path"); const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg"); const char *efisystab = pci_get_param(a, "ecam.efisystab"); #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__) @@ -849,7 +820,7 @@ ecam_detect(struct pci_access *a) else use_acpimcfg = 0; - if (access(efisystab, R_OK)) + if (!efisystab[0] || access(efisystab, R_OK)) { if (efisystab[0]) a->debug("cannot access efisystab: %s: %s...", efisystab, strerror(errno)); @@ -888,16 +859,16 @@ ecam_detect(struct pci_access *a) return 0; } - if (access(devmem, R_OK)) + if (physmem_access(a, 0)) { - a->debug("cannot access physical memory via %s: %s", devmem, strerror(errno)); + a->debug("cannot access physical memory: %s", strerror(errno)); return 0; } if (use_addrs) - a->debug("using %s with ecam addresses %s", devmem, addrs); + a->debug("using with ecam addresses %s", addrs); else - 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" : ""); + a->debug("using with%s%s%s%s%s%s", use_acpimcfg ? " acpimcfg=" : "", use_acpimcfg ? acpimcfg : "", use_efisystab ? " efisystab=" : "", use_efisystab ? efisystab : "", use_bsd ? " bsd" : "", use_x86bios ? " x86bios" : ""); return 1; } @@ -905,7 +876,6 @@ ecam_detect(struct pci_access *a) static void ecam_init(struct pci_access *a) { - const char *devmem = pci_get_param(a, "devmem.path"); const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg"); const char *efisystab = pci_get_param(a, "ecam.efisystab"); #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__) @@ -915,24 +885,32 @@ ecam_init(struct pci_access *a) const char *x86bios = pci_get_param(a, "ecam.x86bios"); #endif const char *addrs = pci_get_param(a, "ecam.addrs"); - struct acpi_mcfg *mcfg = NULL; + struct physmem *physmem = NULL; struct ecam_access *eacc = NULL; + long pagesize = 0; int use_bsd = 0; int use_x86bios = 0; int test_domain = 0; u8 test_bus = 0; volatile void *test_reg; - pagesize = sysconf(_SC_PAGESIZE); - if (pagesize < 0) - a->error("Cannot get page size: %s.", strerror(errno)); - if (!validate_addrs(addrs)) a->error("Option ecam.addrs has invalid address format \"%s\".", addrs); - a->fd = open(devmem, (a->writeable ? O_RDWR : O_RDONLY) | O_DSYNC); - if (a->fd < 0) - a->error("Cannot open %s: %s.", devmem, strerror(errno)); + physmem = physmem_open(a, a->writeable); + if (!physmem) + a->error("Cannot open physcal memory: %s.", strerror(errno)); + + pagesize = physmem_get_pagesize(physmem); + if (pagesize <= 0) + a->error("Cannot get page size: %s.", strerror(errno)); + + eacc = pci_malloc(a, sizeof(*eacc)); + eacc->mcfg = NULL; + eacc->cache = NULL; + eacc->physmem = physmem; + eacc->pagesize = pagesize; + a->backend_data = eacc; if (!*addrs) { @@ -944,18 +922,13 @@ ecam_init(struct pci_access *a) if (strcmp(x86bios, "0") != 0) use_x86bios = 1; #endif - mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios); - if (!mcfg) + eacc->mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios); + if (!eacc->mcfg) a->error("Option ecam.addrs was not specified and ACPI MCFG table cannot be found."); } - eacc = pci_malloc(a, sizeof(*eacc)); - eacc->mcfg = mcfg; - eacc->cache = NULL; - a->backend_data = eacc; - - if (mcfg) - get_mcfg_allocation(mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL); + if (eacc->mcfg) + get_mcfg_allocation(eacc->mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL); else parse_next_addrs(addrs, NULL, &test_domain, &test_bus, NULL, NULL, NULL); @@ -969,16 +942,11 @@ ecam_cleanup(struct pci_access *a) { struct ecam_access *eacc = a->backend_data; - if (a->fd < 0) - return; - munmap_reg(a); + physmem_close(eacc->physmem); pci_mfree(eacc->mcfg); pci_mfree(eacc); a->backend_data = NULL; - - close(a->fd); - a->fd = -1; } static void @@ -1037,13 +1005,13 @@ ecam_read(struct pci_dev *d, int pos, byte *buf, int len) switch (len) { case 1: - buf[0] = readb(reg); + buf[0] = physmem_readb(reg); break; case 2: - ((u16 *) buf)[0] = readw(reg); + ((u16 *) buf)[0] = physmem_readw(reg); break; case 4: - ((u32 *) buf)[0] = readl(reg); + ((u32 *) buf)[0] = physmem_readl(reg); break; } @@ -1067,13 +1035,13 @@ ecam_write(struct pci_dev *d, int pos, byte *buf, int len) switch (len) { case 1: - writeb(buf[0], reg); + physmem_writeb(buf[0], reg); break; case 2: - writew(((u16 *) buf)[0], reg); + physmem_writew(((u16 *) buf)[0], reg); break; case 4: - writel(((u32 *) buf)[0], reg); + physmem_writel(((u32 *) buf)[0], reg); break; } diff --git a/lib/mmio-ports.c b/lib/mmio-ports.c index 9a9b48d..cac8a7e 100644 --- a/lib/mmio-ports.c +++ b/lib/mmio-ports.c @@ -8,64 +8,58 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type - * as 32-bit variant of off_t type is signed and so it cannot represent all - * possible 32-bit offsets. It is required because off_t type is used by mmap(). - */ -#define _FILE_OFFSET_BITS 64 - #include "internal.h" +#include "physmem.h" +#include "physmem-access.h" #include #include #include #include -#include - -#include -#include -#include -#include -#ifndef OFF_MAX -#define OFF_MAX (off_t)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 1) -#endif - -struct mmio_cache -{ - off_t addr_page; - off_t data_page; +struct mmio_cache { + u64 addr_page; + u64 data_page; void *addr_map; void *data_map; }; -static long pagesize; +struct mmio_access { + struct mmio_cache *cache; + struct physmem *physmem; + long pagesize; +}; static void munmap_regs(struct pci_access *a) { - struct mmio_cache *cache = a->backend_data; + struct mmio_access *macc = a->backend_data; + struct mmio_cache *cache = macc->cache; + struct physmem *physmem = macc->physmem; + long pagesize = macc->pagesize; if (!cache) return; - munmap(cache->addr_map, pagesize); + physmem_unmap(physmem, cache->addr_map, pagesize); if (cache->addr_page != cache->data_page) - munmap(cache->data_map, pagesize); + physmem_unmap(physmem, cache->data_map, pagesize); - pci_mfree(a->backend_data); - a->backend_data = NULL; + pci_mfree(macc->cache); + macc->cache = NULL; } static int -mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, volatile void **addr, volatile void **data) +mmap_regs(struct pci_access *a, u64 addr_reg, u64 data_reg, int data_off, volatile void **addr, volatile void **data) { - struct mmio_cache *cache = a->backend_data; - off_t addr_page = addr_reg & ~(pagesize-1); - off_t data_page = data_reg & ~(pagesize-1); - void *addr_map = MAP_FAILED; - void *data_map = MAP_FAILED; + struct mmio_access *macc = a->backend_data; + struct mmio_cache *cache = macc->cache; + struct physmem *physmem = macc->physmem; + long pagesize = macc->pagesize; + u64 addr_page = addr_reg & ~(pagesize-1); + u64 data_page = data_reg & ~(pagesize-1); + void *addr_map = (void *)-1; + void *data_map = (void *)-1; if (cache && cache->addr_page == addr_page) addr_map = cache->addr_map; @@ -73,35 +67,35 @@ mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, vo if (cache && cache->data_page == data_page) data_map = cache->data_map; - if (addr_map == MAP_FAILED) - addr_map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, a->fd, addr_page); + if (addr_map == (void *)-1) + addr_map = physmem_map(physmem, addr_page, pagesize, 1); - if (addr_map == MAP_FAILED) + if (addr_map == (void *)-1) return 0; - if (data_map == MAP_FAILED) + if (data_map == (void *)-1) { if (data_page == addr_page) data_map = addr_map; else - data_map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, a->fd, data_page); + data_map = physmem_map(physmem, data_page, pagesize, 1); } - if (data_map == MAP_FAILED) + if (data_map == (void *)-1) { if (!cache || cache->addr_map != addr_map) - munmap(addr_map, pagesize); + physmem_unmap(physmem, addr_map, pagesize); return 0; } if (cache && cache->addr_page != addr_page) - munmap(cache->addr_map, pagesize); + physmem_unmap(physmem, cache->addr_map, pagesize); if (cache && cache->data_page != data_page && cache->data_page != cache->addr_page) - munmap(cache->data_map, pagesize); + physmem_unmap(physmem, cache->data_map, pagesize); if (!cache) - cache = a->backend_data = pci_malloc(a, sizeof(*cache)); + cache = macc->cache = pci_malloc(a, sizeof(*cache)); cache->addr_page = addr_page; cache->data_page = data_page; @@ -113,47 +107,11 @@ mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, vo return 1; } -static void -writeb(unsigned char value, volatile void *addr) -{ - *(volatile unsigned char *)addr = value; -} - -static void -writew(unsigned short value, volatile void *addr) -{ - *(volatile unsigned short *)addr = value; -} - -static void -writel(u32 value, volatile void *addr) -{ - *(volatile u32 *)addr = value; -} - -static unsigned char -readb(volatile void *addr) -{ - return *(volatile unsigned char *)addr; -} - -static unsigned short -readw(volatile void *addr) -{ - return *(volatile unsigned short *)addr; -} - -static u32 -readl(volatile void *addr) -{ - return *(volatile u32 *)addr; -} - static int validate_addrs(const char *addrs) { const char *sep, *next; - unsigned long long num; + u64 num; char *endptr; if (!*addrs) @@ -174,12 +132,12 @@ validate_addrs(const char *addrs) errno = 0; num = strtoull(addrs, &endptr, 16); - if (errno || endptr != sep || (num & 3) || num > OFF_MAX) + if (errno || endptr != sep || (num & 3)) return 0; errno = 0; num = strtoull(sep+1, &endptr, 16); - if (errno || endptr != next || (num & 3) || num > OFF_MAX) + if (errno || endptr != next || (num & 3)) return 0; if (!*next) @@ -202,7 +160,7 @@ get_domain_count(const char *addrs) } static int -get_domain_addr(const char *addrs, int domain, off_t *addr_reg, off_t *data_reg) +get_domain_addr(const char *addrs, int domain, u64 *addr_reg, u64 *data_reg) { char *endptr; @@ -223,14 +181,14 @@ get_domain_addr(const char *addrs, int domain, off_t *addr_reg, off_t *data_reg) static void conf1_config(struct pci_access *a) { - pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device"); + physmem_init_config(a); pci_define_param(a, "mmio-conf1.addrs", "", "Physical addresses of memory mapped Intel conf1 interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */ } static void conf1_ext_config(struct pci_access *a) { - pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device"); + physmem_init_config(a); pci_define_param(a, "mmio-conf1-ext.addrs", "", "Physical addresses of memory mapped Intel conf1 extended interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */ } @@ -238,7 +196,6 @@ static int detect(struct pci_access *a, char *addrs_param_name) { char *addrs = pci_get_param(a, addrs_param_name); - char *devmem = pci_get_param(a, "devmem.path"); if (!*addrs) { @@ -252,13 +209,13 @@ detect(struct pci_access *a, char *addrs_param_name) return 0; } - if (access(devmem, R_OK | W_OK)) + if (physmem_access(a, 1)) { - a->debug("cannot access %s: %s", devmem, strerror(errno)); + a->debug("cannot access physical memory: %s", strerror(errno)); return 0; } - a->debug("using %s with %s", devmem, addrs); + a->debug("using with %s", addrs); return 1; } @@ -288,11 +245,9 @@ conf1_init(struct pci_access *a) { char *addrs_param_name = get_addrs_param_name(a); char *addrs = pci_get_param(a, addrs_param_name); - char *devmem = pci_get_param(a, "devmem.path"); - - pagesize = sysconf(_SC_PAGESIZE); - if (pagesize < 0) - a->error("Cannot get page size: %s", strerror(errno)); + struct mmio_access *macc; + struct physmem *physmem; + long pagesize; if (!*addrs) a->error("Option %s was not specified.", addrs_param_name); @@ -300,20 +255,29 @@ conf1_init(struct pci_access *a) if (!validate_addrs(addrs)) a->error("Option %s has invalid address format \"%s\".", addrs_param_name, addrs); - a->fd = open(devmem, O_RDWR | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */ - if (a->fd < 0) - a->error("Cannot open %s: %s.", devmem, strerror(errno)); + physmem = physmem_open(a, 1); + if (!physmem) + a->error("Cannot open physcal memory: %s.", strerror(errno)); + + pagesize = physmem_get_pagesize(physmem); + if (pagesize <= 0) + a->error("Cannot get page size: %s.", strerror(errno)); + + macc = pci_malloc(a, sizeof(*macc)); + macc->cache = NULL; + macc->physmem = physmem; + macc->pagesize = pagesize; + a->backend_data = macc; } static void conf1_cleanup(struct pci_access *a) { - if (a->fd < 0) - return; + struct mmio_access *macc = a->backend_data; munmap_regs(a); - close(a->fd); - a->fd = -1; + physmem_close(macc->physmem); + pci_mfree(macc); } static void @@ -334,7 +298,7 @@ conf1_ext_read(struct pci_dev *d, int pos, byte *buf, int len) char *addrs_param_name = get_addrs_param_name(d->access); char *addrs = pci_get_param(d->access, addrs_param_name); volatile void *addr, *data; - off_t addr_reg, data_reg; + u64 addr_reg, data_reg; if (pos >= 4096) return 0; @@ -348,19 +312,19 @@ conf1_ext_read(struct pci_dev *d, int pos, byte *buf, int len) if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data)) return 0; - writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); - readl(addr); /* write barrier for address */ + physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); + physmem_readl(addr); /* write barrier for address */ switch (len) { case 1: - buf[0] = readb(data); + buf[0] = physmem_readb(data); break; case 2: - ((u16 *) buf)[0] = readw(data); + ((u16 *) buf)[0] = physmem_readw(data); break; case 4: - ((u32 *) buf)[0] = readl(data); + ((u32 *) buf)[0] = physmem_readl(data); break; } @@ -382,7 +346,7 @@ conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len) char *addrs_param_name = get_addrs_param_name(d->access); char *addrs = pci_get_param(d->access, addrs_param_name); volatile void *addr, *data; - off_t addr_reg, data_reg; + u64 addr_reg, data_reg; if (pos >= 4096) return 0; @@ -396,19 +360,19 @@ conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len) if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data)) return 0; - writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); - readl(addr); /* write barrier for address */ + physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); + physmem_readl(addr); /* write barrier for address */ switch (len) { case 1: - writeb(buf[0], data); + physmem_writeb(buf[0], data); break; case 2: - writew(((u16 *) buf)[0], data); + physmem_writew(((u16 *) buf)[0], data); break; case 4: - writel(((u32 *) buf)[0], data); + physmem_writel(((u32 *) buf)[0], data); break; } @@ -421,7 +385,7 @@ conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len) * Correct way is to issue CPU instruction for full hw sync barrier but gcc * does not provide any (builtin) function yet. */ - readl(addr); + physmem_readl(addr); return 1; } diff --git a/lib/physmem-access.h b/lib/physmem-access.h new file mode 100644 index 0000000..a4e9744 --- /dev/null +++ b/lib/physmem-access.h @@ -0,0 +1,52 @@ +/* + * The PCI Library -- Compiler-specific wrappers for memory mapped I/O + * + * Copyright (c) 2023 Pali Rohár + * + * Can be freely distributed and used under the terms of the GNU GPL v2+ + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * FIXME + * Unfortunately gcc does not provide architecture independent way to read from + * or write to memory mapped I/O. The best approximation is to use volatile and + * for the write operation follow it by the read operation from the same address. + */ + +static inline void +physmem_writeb(unsigned char value, volatile void *ptr) +{ + *(volatile unsigned char *)ptr = value; +} + +static inline void +physmem_writew(unsigned short value, volatile void *ptr) +{ + *(volatile unsigned short *)ptr = value; +} + +static inline void +physmem_writel(u32 value, volatile void *ptr) +{ + *(volatile u32 *)ptr = value; +} + +static inline unsigned char +physmem_readb(volatile void *ptr) +{ + return *(volatile unsigned char *)ptr; +} + +static inline unsigned short +physmem_readw(volatile void *ptr) +{ + return *(volatile unsigned short *)ptr; +} + +static inline u32 +physmem_readl(volatile void *ptr) +{ + return *(volatile u32 *)ptr; +} diff --git a/lib/physmem-posix.c b/lib/physmem-posix.c new file mode 100644 index 0000000..664ec48 --- /dev/null +++ b/lib/physmem-posix.c @@ -0,0 +1,95 @@ +/* + * The PCI Library -- Physical memory mapping for POSIX systems + * + * Copyright (c) 2023 Pali Rohár + * + * Can be freely distributed and used under the terms of the GNU GPL v2+ + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type + * as 32-bit variant of off_t type is signed and so it cannot represent all + * possible 32-bit offsets. It is required because off_t type is used by mmap(). + */ +#define _FILE_OFFSET_BITS 64 + +#include "internal.h" +#include "physmem.h" + +#include +#include +#include +#include +#include +#include + +#ifndef OFF_MAX +#define OFF_MAX (off_t)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 1) +#endif + +struct physmem { + int fd; +}; + +void +physmem_init_config(struct pci_access *a) +{ + pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device"); +} + +int +physmem_access(struct pci_access *a, int w) +{ + const char *devmem = pci_get_param(a, "devmem.path"); + a->debug("checking access permission of physical memory device %s for %s mode...", devmem, w ? "read/write" : "read-only"); + return access(devmem, R_OK | (w ? W_OK : 0)); +} + +struct physmem * +physmem_open(struct pci_access *a, int w) +{ + const char *devmem = pci_get_param(a, "devmem.path"); + struct physmem *physmem = pci_malloc(a, sizeof(struct physmem)); + + a->debug("trying to open physical memory device %s in %s mode...", devmem, w ? "read/write" : "read-only"); + physmem->fd = open(devmem, (w ? O_RDWR : O_RDONLY) | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */ + if (physmem->fd < 0) + { + pci_mfree(physmem); + return NULL; + } + + return physmem; +} + +void +physmem_close(struct physmem *physmem) +{ + close(physmem->fd); + pci_mfree(physmem); +} + +long +physmem_get_pagesize(struct physmem *physmem UNUSED) +{ + return sysconf(_SC_PAGESIZE); +} + +void * +physmem_map(struct physmem *physmem, u64 addr, size_t length, int w) +{ + if (addr > OFF_MAX) + { + errno = EOVERFLOW; + return (void *)-1; + } + return mmap(NULL, length, PROT_READ | (w ? PROT_WRITE : 0), MAP_SHARED, physmem->fd, addr); +} + +int +physmem_unmap(struct physmem *physmem UNUSED, void *ptr, size_t length) +{ + return munmap(ptr, length); +} diff --git a/lib/physmem.h b/lib/physmem.h new file mode 100644 index 0000000..46ee021 --- /dev/null +++ b/lib/physmem.h @@ -0,0 +1,19 @@ +/* + * The PCI Library -- Physical memory mapping API + * + * Copyright (c) 2023 Pali Rohár + * + * Can be freely distributed and used under the terms of the GNU GPL v2+ + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +struct physmem; + +void physmem_init_config(struct pci_access *a); +int physmem_access(struct pci_access *a, int w); +struct physmem *physmem_open(struct pci_access *a, int w); +void physmem_close(struct physmem *physmem); +long physmem_get_pagesize(struct physmem *physmem); +void *physmem_map(struct physmem *physmem, u64 addr, size_t length, int w); +int physmem_unmap(struct physmem *physmem, void *ptr, size_t length); -- cgit 1.2.3-korg