Skip to content

Instantly share code, notes, and snippets.

@erique
Created October 8, 2021 10:25
Show Gist options
  • Save erique/71f1492f46c46c53636938892a0c593a to your computer and use it in GitHub Desktop.
Save erique/71f1492f46c46c53636938892a0c593a to your computer and use it in GitHub Desktop.
devmem - tool to inspect and manipulate large blocks of physical memory space
/*--------------------------------------------------------------------
* Replay Firmware
* www.fpgaarcade.com
* All rights reserved.
*
* admin@fpgaarcade.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*--------------------------------------------------------------------
*
* Copyright (c) 2021, Erik Hemming
*
*/
// arm-linux-gnueabihf-gcc -Wall -Werror devmem.c -o devmem
// Example usage:
//
// Write a file to physical memory offset 0x20000000 (== 512M)
// $ cat background.raw | ./devmem 0x20000000
//
// Inspect memory at offset 0x20000000
// $ ./devmem 0x20000000 | xxd | less
//
// Read back written data as it's being copied
// $ cat background.raw | ./devmem 0x20000000 | xxd | less
//
// Limit the length of data written data
// $ cat background.raw | ./devmem 0x20000000 65536
//
// Copy a chunk of memory to a file
// $ ./devmem 0x20000000 65536 > memory.bin
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int do_transaction(int fd, off_t offset, char* buffer, size_t length, bool reading, bool writing);
int main(int argc, const char** argv)
{
const bool reading = !isatty(STDOUT_FILENO);
const bool writing = !isatty(STDIN_FILENO);
if (argc < 2 || argc > 3 || (!reading && !writing)) {
fprintf(stderr, "Usage : [ <stdout> | ] %s { address } [ length ] [ | <stdin> ]\n", argv[0]);
return -1;
}
off_t offset = strtoul(argv[1], 0, 0);
size_t length = argc == 3 ? strtoul(argv[2], 0, 0) : (size_t) -1;
fprintf(stderr, "%s address = %08zx\n",
reading && writing ? "Reading and writing" :
reading ? "Reading" : "Writing",
(size_t)offset);
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
fprintf(stderr, "Unable to open '/dev/mem'; %s (%i)\n", strerror(errno), errno);
return -1;
}
size_t processed = 0;
char buf[64 * 1024];
while (length) {
size_t bytes_to_read = length > sizeof(buf) ? sizeof(buf) : length;
ssize_t bytes_read = writing ? read(STDIN_FILENO, buf, bytes_to_read) : bytes_to_read;
if (bytes_read == 0) {
break;
}
int ret = do_transaction(fd, offset, buf, bytes_read, reading, writing);
if (ret) {
fprintf(stderr, "Unable to map '/dev/mem'; %s (%i)\n", strerror(errno), errno);
break;
}
offset += bytes_read;
processed += bytes_read;
length -= bytes_read;
ssize_t bytes_written = reading ? write(STDOUT_FILENO, buf, bytes_read) : 0;
(void) bytes_written;
// fprintf(stderr, "Input = %zi bytes ; Output = %zi bytes\n", bytes_read, bytes_written);
}
close(fd);
fprintf(stderr, "Done; Processed %zi bytes\n", processed);
}
int do_transaction(int fd, off_t offset, char* buffer, size_t length, bool reading, bool writing)
{
const size_t page_size = sysconf(_SC_PAGE_SIZE);
while (length) {
size_t pos_in_page = offset & (page_size - 1);
size_t base_offset = offset - pos_in_page;
size_t sz = page_size - pos_in_page;
if (sz > length) {
sz = length;
}
// fprintf(stderr, "mmap(%08zx); pos_in_page = %zd ; copy %zd bytes\n", base_offset, pos_in_page, sz);
int prot = (reading ? PROT_READ : 0) | (writing ? PROT_WRITE : 0);
char* base = (char*) mmap(0, page_size, prot, MAP_SHARED, fd, base_offset);
if (base == (void*) -1) {
return errno;
}
if (writing) {
memcpy(base + pos_in_page, buffer, sz);
}
if (reading) {
memcpy(buffer, base + pos_in_page, sz);
}
munmap(base, page_size);
offset += sz;
buffer += sz;
length -= sz;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment