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