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