From 8d668d6ed3617cc47425e1413513a2d1f99a25fd Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Tue, 8 Aug 2017 11:56:01 +0100 Subject: [PATCH] Use busybox devmem --- buildroot_config_fragment | 25 ------ busybox_config_fragment | 22 +++++ kernel_module/character_device_create.c | 2 +- kernel_module/pci.c | 2 +- kernel_module/platform_device.c | 2 +- kernel_module/user/devmem3.c | 106 ------------------------ kernel_module/user/usermem.c | 4 +- rootfs_overlay/uio_read.sh | 8 +- rootfs_overlay/virt_to_phys.sh | 8 +- 9 files changed, 35 insertions(+), 144 deletions(-) delete mode 100644 kernel_module/user/devmem3.c diff --git a/buildroot_config_fragment b/buildroot_config_fragment index 36373ff..9b19172 100644 --- a/buildroot_config_fragment +++ b/buildroot_config_fragment @@ -47,31 +47,6 @@ BR2_PACKAGE_DTC=y BR2_PACKAGE_DTC_PROGRAMS=y BR2_PACKAGE_HOST_DTC=y -# On ARM, with our lkmc_platform_device: -# -# devmem2 0x101e9000 w 0x12345678 -# -# Then on QEMU monitor, notice that the registers don't actually change value: -# -# xp/4 0x101e9000 -# -# Uses /dev/mem. -# -# Upstream: http://free-electrons.com/pub/mirror/devmem2.c -# -# See also: -# -# - https://superuser.com/questions/71389/what-is-dev-mem/1214662#1214662 -# - https://unix.stackexchange.com/questions/4948/shell-command-to-read-device-registers -# - man mem -# -# TODO: why with mmap MAP_PRIVATE (used in my previous custom naive version), -# the entire register page is read?; -# -# TODO: have a look at: https://github.com/kaiwan/device-memory-readwrite -# -BR2_PACKAGE_DEVMEM2=y - # Provides setpci and a lspci more advanced than Busybox's # # setpci can read and write to PCI configuration registers. diff --git a/busybox_config_fragment b/busybox_config_fragment index 5e2451e..5f2aa54 100644 --- a/busybox_config_fragment +++ b/busybox_config_fragment @@ -4,3 +4,25 @@ CONFIG_NC=y CONFIG_NC_EXTRA=y CONFIG_NC_SERVER=y CONFIG_STAT=y + +# On ARM, with our lkmc_platform_device: +# +# devmem 0x101e9000 w 0x12345678 +# +# Then on QEMU monitor, notice that the registers don't actually change value: +# +# xp/4 0x101e9000 +# +# Uses /dev/mem. +# +# See also: +# +# - https://superuser.com/questions/71389/what-is-dev-mem/1214662#1214662 +# - https://unix.stackexchange.com/questions/4948/shell-command-to-read-device-registers +# - man mem +# +# TODO: why with mmap MAP_PRIVATE (used in my previous custom naive version), +# the entire register page is read?; +# +# TODO: have a look at: https://github.com/kaiwan/device-memory-readwrite +CONFIG_DEVMEM=y diff --git a/kernel_module/character_device_create.c b/kernel_module/character_device_create.c index 8cd304a..937e1d9 100644 --- a/kernel_module/character_device_create.c +++ b/kernel_module/character_device_create.c @@ -1,7 +1,7 @@ /* Automatically create the device under /dev on insmod, and remove on rmmod. -https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the-init-module-code-of-a-linux-kernel-module +https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the-init-module-code-of-a-linux-kernel-module/45531867#45531867 */ #include diff --git a/kernel_module/pci.c b/kernel_module/pci.c index 862ea7a..990d87b 100644 --- a/kernel_module/pci.c +++ b/kernel_module/pci.c @@ -63,7 +63,7 @@ TODO: does it have any side effects? Set in the edu device at: ## Play with registers from the CLI -Use setpci, devmem2 and /sys. +Use setpci, devmem and /sys. */ #include /* put_user */ diff --git a/kernel_module/platform_device.c b/kernel_module/platform_device.c index 552298d..e0347de 100644 --- a/kernel_module/platform_device.c +++ b/kernel_module/platform_device.c @@ -12,7 +12,7 @@ Expected outcome after insmod: Also without insmodding this module, try: - devmem2 0x101e9000 w 0x12345678 + devmem 0x101e9000 w 0x12345678 which touches from userland through /dev/mem. */ diff --git a/kernel_module/user/devmem3.c b/kernel_module/user/devmem3.c deleted file mode 100644 index 2ffd914..0000000 --- a/kernel_module/user/devmem3.c +++ /dev/null @@ -1,106 +0,0 @@ -/* -Adapted from: http://free-electrons.com/pub/mirror/devmem2.c - -Forked because of the unpredictable access widths: -https://bugs.busybox.net/show_bug.cgi?id=10171 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ - __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0) - -int main(int argc, char **argv) { - int access_type = 'w'; - unsigned long map_size, map_mask; - off_t target; - uintmax_t read_result, writeval; - int fd; - void *map_base, *virt_addr; - - map_size = sysconf(_SC_PAGE_SIZE); - map_mask = map_size - 1; - 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%jX; readback 0x%jX\n", (uintmax_t)writeval, (uintmax_t)read_result); - fflush(stdout); - } - - if(munmap(map_base, map_size) == -1) FATAL; - close(fd); - return 0; -} diff --git a/kernel_module/user/usermem.c b/kernel_module/user/usermem.c index 0bccb43..091f3b1 100644 --- a/kernel_module/user/usermem.c +++ b/kernel_module/user/usermem.c @@ -48,7 +48,7 @@ see: https://stackoverflow.com/questions/11891979/how-to-access-mmaped-dev-mem-w Then: - devmem2 0x7c7b800 + devmem 0x7c7b800 Possible output: @@ -60,7 +60,7 @@ to our physical address and given to the process that mapped /dev/mem. And finally, let's change the value! - devmem2 0x7c7b800 w 0x9abcdef0 + devmem 0x7c7b800 w 0x9abcdef0 After one second, we see on the screen: diff --git a/rootfs_overlay/uio_read.sh b/rootfs_overlay/uio_read.sh index 5cecb26..935f697 100755 --- a/rootfs_overlay/uio_read.sh +++ b/rootfs_overlay/uio_read.sh @@ -8,8 +8,8 @@ echo '1234 11e9' > /sys/bus/pci/drivers/uio_pci_generic/new_id insmod /irq.ko base="$(setpci -d 1234:11e9 BASE_ADDRESS_0)" # Start generating interrupt. -/devmem3.out "0x${base}" w 0x12345678 +devmem "0x${base}" w 0x12345678 # Stop generating interrupt. -/devmem3.out "0x$(($base + 4))" w 0x12345678 -/devmem3.out "0x${base}" w 0x12345678 -/devmem3.out "0x$(($base + 4))" w 0x12345678 +devmem "0x$(($base + 4))" w 0x12345678 +devmem "0x${base}" w 0x12345678 +devmem "0x$(($base + 4))" w 0x12345678 diff --git a/rootfs_overlay/virt_to_phys.sh b/rootfs_overlay/virt_to_phys.sh index 801df46..550f83e 100755 --- a/rootfs_overlay/virt_to_phys.sh +++ b/rootfs_overlay/virt_to_phys.sh @@ -6,11 +6,11 @@ cat lkmc_virt_to_phys # k = 0x12345678 # i = 0x12345678 addr=$(awk '$1 == "virt_to_phys_k" { print $2 }' lkmc_virt_to_phys) -devmem2 "$addr" -devmem2 "$addr" w 0x9ABCDEF0 +devmem "$addr" +devmem "$addr" w 0x9ABCDEF0 addr=$(awk '$1 == "virt_to_phys_i" { print $2 }' lkmc_virt_to_phys) -devmem2 "$addr" -devmem2 "$addr" w 0x9ABCDEF0 +devmem "$addr" +devmem "$addr" w 0x9ABCDEF0 cat lkmc_virt_to_phys # k = 0x9ABCDEF0 # i = 0x12345678