xref: /aosp_15_r20/external/pciutils/lib/physmem-posix.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *      The PCI Library -- Physical memory mapping for POSIX systems
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *      Copyright (c) 2023 Pali Rohár <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker  *
6*c2e0c6b5SAndroid Build Coastguard Worker  *      Can be freely distributed and used under the terms of the GNU GPL v2+
7*c2e0c6b5SAndroid Build Coastguard Worker  *
8*c2e0c6b5SAndroid Build Coastguard Worker  *      SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker  */
10*c2e0c6b5SAndroid Build Coastguard Worker 
11*c2e0c6b5SAndroid Build Coastguard Worker /*
12*c2e0c6b5SAndroid Build Coastguard Worker  * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type
13*c2e0c6b5SAndroid Build Coastguard Worker  * as 32-bit variant of off_t type is signed and so it cannot represent all
14*c2e0c6b5SAndroid Build Coastguard Worker  * possible 32-bit offsets. It is required because off_t type is used by mmap().
15*c2e0c6b5SAndroid Build Coastguard Worker  */
16*c2e0c6b5SAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS 64
17*c2e0c6b5SAndroid Build Coastguard Worker 
18*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
19*c2e0c6b5SAndroid Build Coastguard Worker #include "physmem.h"
20*c2e0c6b5SAndroid Build Coastguard Worker 
21*c2e0c6b5SAndroid Build Coastguard Worker #include <limits.h>
22*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
23*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/mman.h>
24*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/types.h>
25*c2e0c6b5SAndroid Build Coastguard Worker #include <fcntl.h>
26*c2e0c6b5SAndroid Build Coastguard Worker #include <unistd.h>
27*c2e0c6b5SAndroid Build Coastguard Worker 
28*c2e0c6b5SAndroid Build Coastguard Worker #ifndef OFF_MAX
29*c2e0c6b5SAndroid Build Coastguard Worker #define OFF_MAX ((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
30*c2e0c6b5SAndroid Build Coastguard Worker #endif
31*c2e0c6b5SAndroid Build Coastguard Worker 
32*c2e0c6b5SAndroid Build Coastguard Worker struct physmem {
33*c2e0c6b5SAndroid Build Coastguard Worker   int fd;
34*c2e0c6b5SAndroid Build Coastguard Worker };
35*c2e0c6b5SAndroid Build Coastguard Worker 
36*c2e0c6b5SAndroid Build Coastguard Worker void
physmem_init_config(struct pci_access * a)37*c2e0c6b5SAndroid Build Coastguard Worker physmem_init_config(struct pci_access *a)
38*c2e0c6b5SAndroid Build Coastguard Worker {
39*c2e0c6b5SAndroid Build Coastguard Worker   pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
40*c2e0c6b5SAndroid Build Coastguard Worker }
41*c2e0c6b5SAndroid Build Coastguard Worker 
42*c2e0c6b5SAndroid Build Coastguard Worker int
physmem_access(struct pci_access * a,int w)43*c2e0c6b5SAndroid Build Coastguard Worker physmem_access(struct pci_access *a, int w)
44*c2e0c6b5SAndroid Build Coastguard Worker {
45*c2e0c6b5SAndroid Build Coastguard Worker   const char *devmem = pci_get_param(a, "devmem.path");
46*c2e0c6b5SAndroid Build Coastguard Worker   a->debug("checking access permission of physical memory device %s for %s mode...", devmem, w ? "read/write" : "read-only");
47*c2e0c6b5SAndroid Build Coastguard Worker   return access(devmem, R_OK | (w ? W_OK : 0));
48*c2e0c6b5SAndroid Build Coastguard Worker }
49*c2e0c6b5SAndroid Build Coastguard Worker 
50*c2e0c6b5SAndroid Build Coastguard Worker struct physmem *
physmem_open(struct pci_access * a,int w)51*c2e0c6b5SAndroid Build Coastguard Worker physmem_open(struct pci_access *a, int w)
52*c2e0c6b5SAndroid Build Coastguard Worker {
53*c2e0c6b5SAndroid Build Coastguard Worker   const char *devmem = pci_get_param(a, "devmem.path");
54*c2e0c6b5SAndroid Build Coastguard Worker   struct physmem *physmem = pci_malloc(a, sizeof(struct physmem));
55*c2e0c6b5SAndroid Build Coastguard Worker 
56*c2e0c6b5SAndroid Build Coastguard Worker   a->debug("trying to open physical memory device %s in %s mode...", devmem, w ? "read/write" : "read-only");
57*c2e0c6b5SAndroid Build Coastguard Worker   physmem->fd = open(devmem, (w ? O_RDWR : O_RDONLY) | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */
58*c2e0c6b5SAndroid Build Coastguard Worker   if (physmem->fd < 0)
59*c2e0c6b5SAndroid Build Coastguard Worker     {
60*c2e0c6b5SAndroid Build Coastguard Worker       pci_mfree(physmem);
61*c2e0c6b5SAndroid Build Coastguard Worker       return NULL;
62*c2e0c6b5SAndroid Build Coastguard Worker     }
63*c2e0c6b5SAndroid Build Coastguard Worker 
64*c2e0c6b5SAndroid Build Coastguard Worker   return physmem;
65*c2e0c6b5SAndroid Build Coastguard Worker }
66*c2e0c6b5SAndroid Build Coastguard Worker 
67*c2e0c6b5SAndroid Build Coastguard Worker void
physmem_close(struct physmem * physmem)68*c2e0c6b5SAndroid Build Coastguard Worker physmem_close(struct physmem *physmem)
69*c2e0c6b5SAndroid Build Coastguard Worker {
70*c2e0c6b5SAndroid Build Coastguard Worker   close(physmem->fd);
71*c2e0c6b5SAndroid Build Coastguard Worker   pci_mfree(physmem);
72*c2e0c6b5SAndroid Build Coastguard Worker }
73*c2e0c6b5SAndroid Build Coastguard Worker 
74*c2e0c6b5SAndroid Build Coastguard Worker long
physmem_get_pagesize(struct physmem * physmem UNUSED)75*c2e0c6b5SAndroid Build Coastguard Worker physmem_get_pagesize(struct physmem *physmem UNUSED)
76*c2e0c6b5SAndroid Build Coastguard Worker {
77*c2e0c6b5SAndroid Build Coastguard Worker   return sysconf(_SC_PAGESIZE);
78*c2e0c6b5SAndroid Build Coastguard Worker }
79*c2e0c6b5SAndroid Build Coastguard Worker 
80*c2e0c6b5SAndroid Build Coastguard Worker void *
physmem_map(struct physmem * physmem,u64 addr,size_t length,int w)81*c2e0c6b5SAndroid Build Coastguard Worker physmem_map(struct physmem *physmem, u64 addr, size_t length, int w)
82*c2e0c6b5SAndroid Build Coastguard Worker {
83*c2e0c6b5SAndroid Build Coastguard Worker   if (addr > OFF_MAX)
84*c2e0c6b5SAndroid Build Coastguard Worker     {
85*c2e0c6b5SAndroid Build Coastguard Worker       errno = EOVERFLOW;
86*c2e0c6b5SAndroid Build Coastguard Worker       return (void *)-1;
87*c2e0c6b5SAndroid Build Coastguard Worker     }
88*c2e0c6b5SAndroid Build Coastguard Worker   return mmap(NULL, length, PROT_READ | (w ? PROT_WRITE : 0), MAP_SHARED, physmem->fd, addr);
89*c2e0c6b5SAndroid Build Coastguard Worker }
90*c2e0c6b5SAndroid Build Coastguard Worker 
91*c2e0c6b5SAndroid Build Coastguard Worker int
physmem_unmap(struct physmem * physmem UNUSED,void * ptr,size_t length)92*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(struct physmem *physmem UNUSED, void *ptr, size_t length)
93*c2e0c6b5SAndroid Build Coastguard Worker {
94*c2e0c6b5SAndroid Build Coastguard Worker   return munmap(ptr, length);
95*c2e0c6b5SAndroid Build Coastguard Worker }
96