This commit is contained in:
Ciro Santilli
2017-08-05 21:18:57 +01:00
parent 83411a0597
commit d871c008fb
5 changed files with 161 additions and 8 deletions

View File

@@ -0,0 +1,103 @@
/*
Adapted from: http://free-electrons.com/pub/mirror/devmem2.c
*/
#include <stdio.h>
#include <stdlib.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>
#include <stdint.h>
#define FATAL 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;
uintmax_t read_result, writeval;
off_t target;
int access_type = 'w';
if(argc < 2) {
fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n"
"\taddress : memory address to act upon\n"
"\ttype : access operation type : [b]yte, [h]alfword, [w]ord\n"
"\tdata : data to be written\n\n",
argv[0]);
exit(1);
}
target = strtoul(argv[1], 0, 0);
if(argc > 2)
access_type = tolower(argv[2][0]);
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
printf("/dev/mem opened.\n");
fflush(stdout);
/* Map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
if(map_base == (void *) -1) FATAL;
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
virt_addr = map_base + (target & MAP_MASK);
switch(access_type) {
case 'b':
read_result = *((uint8_t *) virt_addr);
break;
case 'h':
read_result = *((uint16_t *) virt_addr);
break;
case 'w':
read_result = *((uint32_t *) virt_addr);
break;
case 'q':
read_result = *((uint64_t *) virt_addr);
break;
default:
fprintf(stderr, "Illegal data type '%c'.\n", access_type);
exit(2);
}
printf("Value at address 0x%jX (%p): 0x%jX\n", (uintmax_t)target, virt_addr, (uintmax_t)read_result);
fflush(stdout);
if(argc > 3) {
writeval = strtoul(argv[3], 0, 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 'q':
*((uint64_t *) virt_addr) = writeval;
read_result = *((uint64_t *) virt_addr);
break;
}
printf("Written 0x%X; readback 0x%jX\n", (unsigned int)writeval, (unsigned int)read_result);
fflush(stdout);
}
if(munmap(map_base, MAP_SIZE) == -1) FATAL;
close(fd);
return 0;
}

View File

@@ -1,9 +1,15 @@
/*
Adapted from: https://yurovsky.github.io/2014/10/10/linux-uio-gpio-interrupt/
modprobe uio_pdrv_genirq
modprobe uio_pci_generic
echo '1234 11e9' > /sys/bus/pci/drivers/uio_pci_generic/new_id
/uio_read.out &
TODO get working.
TODO get working. The problem now is how to generate IRQs to test our IRQ handling:
- a synchronous IRQ needs regwrites to be kicked off, but mmap does not seem to work with this driver
- a custom PCI periodic timer device would also need to be initiazed by some regwrite, otherwise
early interrupts before the OS is setup would crash everything?
Handle interrupts from userland and print a message to stdout.
*/
@@ -17,17 +23,31 @@ Handle interrupts from userland and print a message to stdout.
#include <sys/types.h>
#include <unistd.h> /* write */
#include <assert.h>
#include <sys/mman.h>
int main(int argc, char **argv)
{
char *dev;
if (argc < 2) {
char *dev = "/dev/uio0";
if (argc > 1) {
dev = argv[1];
exit(EXIT_FAILURE);
}
int fd = open("/dev/uio", O_RDWR);
int fd = open(dev, O_RDWR);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
/* TODO not supported by this kernel module? */
/*int *addr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);*/
/*if (addr == MAP_FAILED) {*/
/*perror("mmap");*/
/*assert(0);*/
/*}*/
/**addr = 0x12345678;*/
while (1) {
uint32_t info = 1;
size_t nb = write(fd, &info, sizeof(info));