Created
January 2, 2018 08:04
-
-
Save bensenq/cf39f91f8c07b97f9d95b2e6761198d6 to your computer and use it in GitHub Desktop.
The pcimem application provides a simple method of reading and writing to memory registers on a PCI card. https://github.com/billfarrow/pcimem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * pcimem.c: Simple program to read/write from/to a pci device from userspace. | |
| * | |
| * Copyright (C) 2010, Bill Farrow ([email protected]) | |
| * | |
| * Based on the devmem2.c code | |
| * Copyright (C) 2000, Jan-Derk Bakker ([email protected]) | |
| * | |
| * This program is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation; either version 2 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| * | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <signal.h> | |
| #include <fcntl.h> | |
| #include <ctype.h> | |
| #include <termios.h> | |
| #include <sys/types.h> | |
| #include <sys/mman.h> | |
| #define PRINT_ERROR \ | |
| do { \ | |
| fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ | |
| __LINE__, __FILE__, errno, strerror(errno)); exit(1); \ | |
| } while(0) | |
| #define MAP_SIZE 4096UL | |
| #define MAP_MASK (MAP_SIZE - 1) | |
| int main(int argc, char **argv) { | |
| int fd; | |
| void *map_base, *virt_addr; | |
| uint64_t read_result, writeval; | |
| char *filename; | |
| off_t target; | |
| int access_type = 'w'; | |
| int type_width; | |
| if(argc < 3) { | |
| // pcimem /sys/bus/pci/devices/0001\:00\:07.0/resource0 0x100 w 0x00 | |
| // argv[0] [1] [2] [3] [4] | |
| fprintf(stderr, "\nUsage:\t%s { sys file } { offset } [ type [ data ] ]\n" | |
| "\tsys file: sysfs file for the pci resource to act on\n" | |
| "\toffset : offset into pci memory region to act upon\n" | |
| "\ttype : access operation type : [b]yte, [h]alfword, [w]ord, [d]ouble-word\n" | |
| "\tdata : data to be written\n\n", | |
| argv[0]); | |
| exit(1); | |
| } | |
| filename = argv[1]; | |
| target = strtoul(argv[2], 0, 0); | |
| if(argc > 3) | |
| access_type = tolower(argv[3][0]); | |
| if((fd = open(filename, O_RDWR | O_SYNC)) == -1) PRINT_ERROR; | |
| printf("%s opened.\n", filename); | |
| printf("Target offset is 0x%x, page size is %ld\n", (int) target, sysconf(_SC_PAGE_SIZE)); | |
| fflush(stdout); | |
| /* Map one page */ | |
| printf("mmap(%d, %ld, 0x%x, 0x%x, %d, 0x%x)\n", 0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (int) target); | |
| map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); | |
| if(map_base == (void *) -1) PRINT_ERROR; | |
| printf("PCI Memory mapped to address 0x%08lx.\n", (unsigned long) map_base); | |
| fflush(stdout); | |
| virt_addr = map_base + (target & MAP_MASK); | |
| switch(access_type) { | |
| case 'b': | |
| read_result = *((uint8_t *) virt_addr); | |
| type_width = 2; | |
| break; | |
| case 'h': | |
| read_result = *((uint16_t *) virt_addr); | |
| type_width = 4; | |
| break; | |
| case 'w': | |
| read_result = *((uint32_t *) virt_addr); | |
| type_width = 8; | |
| break; | |
| case 'd': | |
| read_result = *((uint64_t *) virt_addr); | |
| type_width = 16; | |
| break; | |
| default: | |
| fprintf(stderr, "Illegal data type '%c'.\n", access_type); | |
| exit(2); | |
| } | |
| printf("Value at offset 0x%X (%p): 0x%0*lX\n", (int) target, virt_addr, type_width, | |
| read_result); | |
| fflush(stdout); | |
| if(argc > 4) { | |
| writeval = strtoull(argv[4], NULL, 0); | |
| switch(access_type) { | |
| case 'b': | |
| *((uint8_t *) virt_addr) = writeval; | |
| read_result = *((uint8_t *) virt_addr); | |
| break; | |
| case 'h': | |
| *((uint16_t *) virt_addr) = writeval; | |
| read_result = *((uint16_t *) virt_addr); | |
| break; | |
| case 'w': | |
| *((uint32_t *) virt_addr) = writeval; | |
| read_result = *((uint32_t *) virt_addr); | |
| break; | |
| case 'd': | |
| *((uint64_t *) virt_addr) = writeval; | |
| read_result = *((uint64_t *) virt_addr); | |
| break; | |
| } | |
| printf("Written 0x%0*lX; readback 0x%*lX\n", type_width, | |
| writeval, type_width, read_result); | |
| fflush(stdout); | |
| } | |
| if(munmap(map_base, MAP_SIZE) == -1) PRINT_ERROR; | |
| close(fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment