1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-only
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker * Exercise /dev/mem mmap cases that have been troublesome in the past
4*053f45beSAndroid Build Coastguard Worker *
5*053f45beSAndroid Build Coastguard Worker * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
6*053f45beSAndroid Build Coastguard Worker * Bjorn Helgaas <[email protected]>
7*053f45beSAndroid Build Coastguard Worker */
8*053f45beSAndroid Build Coastguard Worker
9*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
10*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
11*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
12*053f45beSAndroid Build Coastguard Worker #include <dirent.h>
13*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
14*053f45beSAndroid Build Coastguard Worker #include <fnmatch.h>
15*053f45beSAndroid Build Coastguard Worker #include <string.h>
16*053f45beSAndroid Build Coastguard Worker #include <sys/ioctl.h>
17*053f45beSAndroid Build Coastguard Worker #include <sys/mman.h>
18*053f45beSAndroid Build Coastguard Worker #include <sys/stat.h>
19*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
20*053f45beSAndroid Build Coastguard Worker #include <linux/pci.h>
21*053f45beSAndroid Build Coastguard Worker
22*053f45beSAndroid Build Coastguard Worker int sum;
23*053f45beSAndroid Build Coastguard Worker
map_mem(char * path,off_t offset,size_t length,int touch)24*053f45beSAndroid Build Coastguard Worker static int map_mem(char *path, off_t offset, size_t length, int touch)
25*053f45beSAndroid Build Coastguard Worker {
26*053f45beSAndroid Build Coastguard Worker int fd, rc;
27*053f45beSAndroid Build Coastguard Worker void *addr;
28*053f45beSAndroid Build Coastguard Worker int *c;
29*053f45beSAndroid Build Coastguard Worker
30*053f45beSAndroid Build Coastguard Worker fd = open(path, O_RDWR);
31*053f45beSAndroid Build Coastguard Worker if (fd == -1) {
32*053f45beSAndroid Build Coastguard Worker perror(path);
33*053f45beSAndroid Build Coastguard Worker return -1;
34*053f45beSAndroid Build Coastguard Worker }
35*053f45beSAndroid Build Coastguard Worker
36*053f45beSAndroid Build Coastguard Worker if (fnmatch("/proc/bus/pci/*", path, 0) == 0) {
37*053f45beSAndroid Build Coastguard Worker rc = ioctl(fd, PCIIOC_MMAP_IS_MEM);
38*053f45beSAndroid Build Coastguard Worker if (rc == -1)
39*053f45beSAndroid Build Coastguard Worker perror("PCIIOC_MMAP_IS_MEM ioctl");
40*053f45beSAndroid Build Coastguard Worker }
41*053f45beSAndroid Build Coastguard Worker
42*053f45beSAndroid Build Coastguard Worker addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
43*053f45beSAndroid Build Coastguard Worker if (addr == MAP_FAILED)
44*053f45beSAndroid Build Coastguard Worker return 1;
45*053f45beSAndroid Build Coastguard Worker
46*053f45beSAndroid Build Coastguard Worker if (touch) {
47*053f45beSAndroid Build Coastguard Worker c = (int *) addr;
48*053f45beSAndroid Build Coastguard Worker while (c < (int *) (addr + length))
49*053f45beSAndroid Build Coastguard Worker sum += *c++;
50*053f45beSAndroid Build Coastguard Worker }
51*053f45beSAndroid Build Coastguard Worker
52*053f45beSAndroid Build Coastguard Worker rc = munmap(addr, length);
53*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
54*053f45beSAndroid Build Coastguard Worker perror("munmap");
55*053f45beSAndroid Build Coastguard Worker return -1;
56*053f45beSAndroid Build Coastguard Worker }
57*053f45beSAndroid Build Coastguard Worker
58*053f45beSAndroid Build Coastguard Worker close(fd);
59*053f45beSAndroid Build Coastguard Worker return 0;
60*053f45beSAndroid Build Coastguard Worker }
61*053f45beSAndroid Build Coastguard Worker
scan_tree(char * path,char * file,off_t offset,size_t length,int touch)62*053f45beSAndroid Build Coastguard Worker static int scan_tree(char *path, char *file, off_t offset, size_t length, int touch)
63*053f45beSAndroid Build Coastguard Worker {
64*053f45beSAndroid Build Coastguard Worker struct dirent **namelist;
65*053f45beSAndroid Build Coastguard Worker char *name, *path2;
66*053f45beSAndroid Build Coastguard Worker int i, n, r, rc = 0, result = 0;
67*053f45beSAndroid Build Coastguard Worker struct stat buf;
68*053f45beSAndroid Build Coastguard Worker
69*053f45beSAndroid Build Coastguard Worker n = scandir(path, &namelist, 0, alphasort);
70*053f45beSAndroid Build Coastguard Worker if (n < 0) {
71*053f45beSAndroid Build Coastguard Worker perror("scandir");
72*053f45beSAndroid Build Coastguard Worker return -1;
73*053f45beSAndroid Build Coastguard Worker }
74*053f45beSAndroid Build Coastguard Worker
75*053f45beSAndroid Build Coastguard Worker for (i = 0; i < n; i++) {
76*053f45beSAndroid Build Coastguard Worker name = namelist[i]->d_name;
77*053f45beSAndroid Build Coastguard Worker
78*053f45beSAndroid Build Coastguard Worker if (fnmatch(".", name, 0) == 0)
79*053f45beSAndroid Build Coastguard Worker goto skip;
80*053f45beSAndroid Build Coastguard Worker if (fnmatch("..", name, 0) == 0)
81*053f45beSAndroid Build Coastguard Worker goto skip;
82*053f45beSAndroid Build Coastguard Worker
83*053f45beSAndroid Build Coastguard Worker path2 = malloc(strlen(path) + strlen(name) + 3);
84*053f45beSAndroid Build Coastguard Worker strcpy(path2, path);
85*053f45beSAndroid Build Coastguard Worker strcat(path2, "/");
86*053f45beSAndroid Build Coastguard Worker strcat(path2, name);
87*053f45beSAndroid Build Coastguard Worker
88*053f45beSAndroid Build Coastguard Worker if (fnmatch(file, name, 0) == 0) {
89*053f45beSAndroid Build Coastguard Worker rc = map_mem(path2, offset, length, touch);
90*053f45beSAndroid Build Coastguard Worker if (rc == 0)
91*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
92*053f45beSAndroid Build Coastguard Worker else if (rc > 0)
93*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
94*053f45beSAndroid Build Coastguard Worker else {
95*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
96*053f45beSAndroid Build Coastguard Worker return rc;
97*053f45beSAndroid Build Coastguard Worker }
98*053f45beSAndroid Build Coastguard Worker } else {
99*053f45beSAndroid Build Coastguard Worker r = lstat(path2, &buf);
100*053f45beSAndroid Build Coastguard Worker if (r == 0 && S_ISDIR(buf.st_mode)) {
101*053f45beSAndroid Build Coastguard Worker rc = scan_tree(path2, file, offset, length, touch);
102*053f45beSAndroid Build Coastguard Worker if (rc < 0)
103*053f45beSAndroid Build Coastguard Worker return rc;
104*053f45beSAndroid Build Coastguard Worker }
105*053f45beSAndroid Build Coastguard Worker }
106*053f45beSAndroid Build Coastguard Worker
107*053f45beSAndroid Build Coastguard Worker result |= rc;
108*053f45beSAndroid Build Coastguard Worker free(path2);
109*053f45beSAndroid Build Coastguard Worker
110*053f45beSAndroid Build Coastguard Worker skip:
111*053f45beSAndroid Build Coastguard Worker free(namelist[i]);
112*053f45beSAndroid Build Coastguard Worker }
113*053f45beSAndroid Build Coastguard Worker free(namelist);
114*053f45beSAndroid Build Coastguard Worker return result;
115*053f45beSAndroid Build Coastguard Worker }
116*053f45beSAndroid Build Coastguard Worker
117*053f45beSAndroid Build Coastguard Worker char buf[1024];
118*053f45beSAndroid Build Coastguard Worker
read_rom(char * path)119*053f45beSAndroid Build Coastguard Worker static int read_rom(char *path)
120*053f45beSAndroid Build Coastguard Worker {
121*053f45beSAndroid Build Coastguard Worker int fd, rc;
122*053f45beSAndroid Build Coastguard Worker size_t size = 0;
123*053f45beSAndroid Build Coastguard Worker
124*053f45beSAndroid Build Coastguard Worker fd = open(path, O_RDWR);
125*053f45beSAndroid Build Coastguard Worker if (fd == -1) {
126*053f45beSAndroid Build Coastguard Worker perror(path);
127*053f45beSAndroid Build Coastguard Worker return -1;
128*053f45beSAndroid Build Coastguard Worker }
129*053f45beSAndroid Build Coastguard Worker
130*053f45beSAndroid Build Coastguard Worker rc = write(fd, "1", 2);
131*053f45beSAndroid Build Coastguard Worker if (rc <= 0) {
132*053f45beSAndroid Build Coastguard Worker close(fd);
133*053f45beSAndroid Build Coastguard Worker perror("write");
134*053f45beSAndroid Build Coastguard Worker return -1;
135*053f45beSAndroid Build Coastguard Worker }
136*053f45beSAndroid Build Coastguard Worker
137*053f45beSAndroid Build Coastguard Worker do {
138*053f45beSAndroid Build Coastguard Worker rc = read(fd, buf, sizeof(buf));
139*053f45beSAndroid Build Coastguard Worker if (rc > 0)
140*053f45beSAndroid Build Coastguard Worker size += rc;
141*053f45beSAndroid Build Coastguard Worker } while (rc > 0);
142*053f45beSAndroid Build Coastguard Worker
143*053f45beSAndroid Build Coastguard Worker close(fd);
144*053f45beSAndroid Build Coastguard Worker return size;
145*053f45beSAndroid Build Coastguard Worker }
146*053f45beSAndroid Build Coastguard Worker
scan_rom(char * path,char * file)147*053f45beSAndroid Build Coastguard Worker static int scan_rom(char *path, char *file)
148*053f45beSAndroid Build Coastguard Worker {
149*053f45beSAndroid Build Coastguard Worker struct dirent **namelist;
150*053f45beSAndroid Build Coastguard Worker char *name, *path2;
151*053f45beSAndroid Build Coastguard Worker int i, n, r, rc = 0, result = 0;
152*053f45beSAndroid Build Coastguard Worker struct stat buf;
153*053f45beSAndroid Build Coastguard Worker
154*053f45beSAndroid Build Coastguard Worker n = scandir(path, &namelist, 0, alphasort);
155*053f45beSAndroid Build Coastguard Worker if (n < 0) {
156*053f45beSAndroid Build Coastguard Worker perror("scandir");
157*053f45beSAndroid Build Coastguard Worker return -1;
158*053f45beSAndroid Build Coastguard Worker }
159*053f45beSAndroid Build Coastguard Worker
160*053f45beSAndroid Build Coastguard Worker for (i = 0; i < n; i++) {
161*053f45beSAndroid Build Coastguard Worker name = namelist[i]->d_name;
162*053f45beSAndroid Build Coastguard Worker
163*053f45beSAndroid Build Coastguard Worker if (fnmatch(".", name, 0) == 0)
164*053f45beSAndroid Build Coastguard Worker goto skip;
165*053f45beSAndroid Build Coastguard Worker if (fnmatch("..", name, 0) == 0)
166*053f45beSAndroid Build Coastguard Worker goto skip;
167*053f45beSAndroid Build Coastguard Worker
168*053f45beSAndroid Build Coastguard Worker path2 = malloc(strlen(path) + strlen(name) + 3);
169*053f45beSAndroid Build Coastguard Worker strcpy(path2, path);
170*053f45beSAndroid Build Coastguard Worker strcat(path2, "/");
171*053f45beSAndroid Build Coastguard Worker strcat(path2, name);
172*053f45beSAndroid Build Coastguard Worker
173*053f45beSAndroid Build Coastguard Worker if (fnmatch(file, name, 0) == 0) {
174*053f45beSAndroid Build Coastguard Worker rc = read_rom(path2);
175*053f45beSAndroid Build Coastguard Worker
176*053f45beSAndroid Build Coastguard Worker /*
177*053f45beSAndroid Build Coastguard Worker * It's OK if the ROM is unreadable. Maybe there
178*053f45beSAndroid Build Coastguard Worker * is no ROM, or some other error occurred. The
179*053f45beSAndroid Build Coastguard Worker * important thing is that no MCA happened.
180*053f45beSAndroid Build Coastguard Worker */
181*053f45beSAndroid Build Coastguard Worker if (rc > 0)
182*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: %s read %d bytes\n", path2, rc);
183*053f45beSAndroid Build Coastguard Worker else {
184*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: %s not readable\n", path2);
185*053f45beSAndroid Build Coastguard Worker return rc;
186*053f45beSAndroid Build Coastguard Worker }
187*053f45beSAndroid Build Coastguard Worker } else {
188*053f45beSAndroid Build Coastguard Worker r = lstat(path2, &buf);
189*053f45beSAndroid Build Coastguard Worker if (r == 0 && S_ISDIR(buf.st_mode)) {
190*053f45beSAndroid Build Coastguard Worker rc = scan_rom(path2, file);
191*053f45beSAndroid Build Coastguard Worker if (rc < 0)
192*053f45beSAndroid Build Coastguard Worker return rc;
193*053f45beSAndroid Build Coastguard Worker }
194*053f45beSAndroid Build Coastguard Worker }
195*053f45beSAndroid Build Coastguard Worker
196*053f45beSAndroid Build Coastguard Worker result |= rc;
197*053f45beSAndroid Build Coastguard Worker free(path2);
198*053f45beSAndroid Build Coastguard Worker
199*053f45beSAndroid Build Coastguard Worker skip:
200*053f45beSAndroid Build Coastguard Worker free(namelist[i]);
201*053f45beSAndroid Build Coastguard Worker }
202*053f45beSAndroid Build Coastguard Worker free(namelist);
203*053f45beSAndroid Build Coastguard Worker return result;
204*053f45beSAndroid Build Coastguard Worker }
205*053f45beSAndroid Build Coastguard Worker
main(void)206*053f45beSAndroid Build Coastguard Worker int main(void)
207*053f45beSAndroid Build Coastguard Worker {
208*053f45beSAndroid Build Coastguard Worker int rc;
209*053f45beSAndroid Build Coastguard Worker
210*053f45beSAndroid Build Coastguard Worker if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
211*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
212*053f45beSAndroid Build Coastguard Worker else
213*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
214*053f45beSAndroid Build Coastguard Worker
215*053f45beSAndroid Build Coastguard Worker /*
216*053f45beSAndroid Build Coastguard Worker * It's not safe to blindly read the VGA frame buffer. If you know
217*053f45beSAndroid Build Coastguard Worker * how to poke the card the right way, it should respond, but it's
218*053f45beSAndroid Build Coastguard Worker * not safe in general. Many machines, e.g., Intel chipsets, cover
219*053f45beSAndroid Build Coastguard Worker * up a non-responding card by just returning -1, but others will
220*053f45beSAndroid Build Coastguard Worker * report the failure as a machine check.
221*053f45beSAndroid Build Coastguard Worker */
222*053f45beSAndroid Build Coastguard Worker if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
223*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
224*053f45beSAndroid Build Coastguard Worker else
225*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
226*053f45beSAndroid Build Coastguard Worker
227*053f45beSAndroid Build Coastguard Worker if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
228*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
229*053f45beSAndroid Build Coastguard Worker else
230*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
231*053f45beSAndroid Build Coastguard Worker
232*053f45beSAndroid Build Coastguard Worker /*
233*053f45beSAndroid Build Coastguard Worker * Often you can map all the individual pieces above (0-0xA0000,
234*053f45beSAndroid Build Coastguard Worker * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
235*053f45beSAndroid Build Coastguard Worker * thing at once. This is because the individual pieces use different
236*053f45beSAndroid Build Coastguard Worker * attributes, and there's no single attribute supported over the
237*053f45beSAndroid Build Coastguard Worker * whole region.
238*053f45beSAndroid Build Coastguard Worker */
239*053f45beSAndroid Build Coastguard Worker rc = map_mem("/dev/mem", 0, 1024*1024, 0);
240*053f45beSAndroid Build Coastguard Worker if (rc == 0)
241*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
242*053f45beSAndroid Build Coastguard Worker else if (rc > 0)
243*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
244*053f45beSAndroid Build Coastguard Worker else
245*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
246*053f45beSAndroid Build Coastguard Worker
247*053f45beSAndroid Build Coastguard Worker scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
248*053f45beSAndroid Build Coastguard Worker scan_tree("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
249*053f45beSAndroid Build Coastguard Worker scan_tree("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
250*053f45beSAndroid Build Coastguard Worker scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
251*053f45beSAndroid Build Coastguard Worker
252*053f45beSAndroid Build Coastguard Worker scan_rom("/sys/devices", "rom");
253*053f45beSAndroid Build Coastguard Worker
254*053f45beSAndroid Build Coastguard Worker scan_tree("/proc/bus/pci", "??.?", 0, 0xA0000, 1);
255*053f45beSAndroid Build Coastguard Worker scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0);
256*053f45beSAndroid Build Coastguard Worker scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1);
257*053f45beSAndroid Build Coastguard Worker scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0);
258*053f45beSAndroid Build Coastguard Worker
259*053f45beSAndroid Build Coastguard Worker return rc;
260*053f45beSAndroid Build Coastguard Worker }
261